diff options
82 files changed, 14879 insertions, 12641 deletions
diff --git a/src/compiler/scala/reflect/common/AnnotationCheckers.scala b/src/compiler/scala/reflect/common/AnnotationCheckers.scala new file mode 100644 index 0000000000..cd3b343238 --- /dev/null +++ b/src/compiler/scala/reflect/common/AnnotationCheckers.scala @@ -0,0 +1,120 @@ +/* NSC -- new Scala compiler + * Copyright 2007-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +/** Additions to the type checker that can be added at + * run time. Typically these are added by + * compiler plugins. */ +trait AnnotationCheckers { + self: SymbolTable => + + + /** An additional checker for annotations on types. + * Typically these are registered by compiler plugins + * with the addAnnotationChecker method. */ + abstract class AnnotationChecker { + /** Check the annotations on two types conform. */ + def annotationsConform(tpe1: Type, tpe2: Type): Boolean + + /** Refine the computed least upper bound of a list of types. + * All this should do is add annotations. */ + def annotationsLub(tp: Type, ts: List[Type]): Type = tp + + /** Refine the computed greatest lower bound of a list of types. + * All this should do is add annotations. */ + def annotationsGlb(tp: Type, ts: List[Type]): Type = tp + + /** Refine the bounds on type parameters to the given type arguments. */ + def adaptBoundsToAnnotations(bounds: List[TypeBounds], + tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = bounds + + /** Modify the type that has thus far been inferred + * for a tree. All this should do is add annotations. */ + def addAnnotations(tree: Tree, tpe: Type): Type = tpe + + /** Decide whether this annotation checker can adapt a tree + * that has an annotated type to the given type tp, taking + * into account the given mode (see method adapt in trait Typers).*/ + def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = false + + /** Adapt a tree that has an annotated type to the given type tp, + * taking into account the given mode (see method adapt in trait Typers). + * An implementation cannot rely on canAdaptAnnotations being called + * before. If the implementing class cannot do the adaptiong, it + * should return the tree unchanged.*/ + def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = tree + } + + /** The list of annotation checkers that have been registered */ + private var annotationCheckers: List[AnnotationChecker] = Nil + + /** Register an annotation checker. Typically these + * are added by compiler plugins. */ + def addAnnotationChecker(checker: AnnotationChecker) { + if (!(annotationCheckers contains checker)) + annotationCheckers = checker :: annotationCheckers + } + + /** Remove all annotation checkers */ + def removeAllAnnotationCheckers() { + annotationCheckers = Nil + } + + /** Check that the annotations on two types conform. To do + * so, consult all registered annotation checkers. */ + def annotationsConform(tp1: Type, tp2: Type): Boolean = { + /* Finish quickly if there are no annotations */ + if (tp1.annotations.isEmpty && tp2.annotations.isEmpty) + true + else + annotationCheckers.forall( + _.annotationsConform(tp1,tp2)) + } + + /** Refine the computed least upper bound of a list of types. + * All this should do is add annotations. */ + def annotationsLub(tpe: Type, ts: List[Type]): Type = { + annotationCheckers.foldLeft(tpe)((tpe, checker) => + checker.annotationsLub(tpe, ts)) + } + + /** Refine the computed greatest lower bound of a list of types. + * All this should do is add annotations. */ + def annotationsGlb(tpe: Type, ts: List[Type]): Type = { + annotationCheckers.foldLeft(tpe)((tpe, checker) => + checker.annotationsGlb(tpe, ts)) + } + + /** Refine the bounds on type parameters to the given type arguments. */ + def adaptBoundsToAnnotations(bounds: List[TypeBounds], + tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = { + annotationCheckers.foldLeft(bounds)((bounds, checker) => + checker.adaptBoundsToAnnotations(bounds, tparams, targs)) + } + + /** Let all annotations checkers add extra annotations + * to this tree's type. */ + def addAnnotations(tree: Tree, tpe: Type): Type = { + annotationCheckers.foldLeft(tpe)((tpe, checker) => + checker.addAnnotations(tree, tpe)) + } + + /** Find out whether any annotation checker can adapt a tree + * to a given type. Called by Typers.adapt. */ + def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = { + annotationCheckers.exists(_.canAdaptAnnotations(tree, mode, pt)) + } + + /** Let registered annotation checkers adapt a tree + * to a given type (called by Typers.adapt). Annotation checkers + * that cannot do the adaption should pass the tree through + * unchanged. */ + def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = { + annotationCheckers.foldLeft(tree)((tree, checker) => + checker.adaptAnnotations(tree, mode, pt)) + } +} diff --git a/src/compiler/scala/reflect/common/AnnotationInfos.scala b/src/compiler/scala/reflect/common/AnnotationInfos.scala new file mode 100644 index 0000000000..642e2f0b22 --- /dev/null +++ b/src/compiler/scala/reflect/common/AnnotationInfos.scala @@ -0,0 +1,143 @@ +/* NSC -- new Scala compiler + * Copyright 2007-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +import util._ + +/** AnnotationInfo and its helpers */ +trait AnnotationInfos /*extends reflect.generic.AnnotationInfos*/ { self: SymbolTable => + + /** Arguments to classfile annotations (which are written to + * bytecode as java annotations) are either: + * <ul> + * <li>constants</li> + * <li>arrays of constants</li> + * <li>or nested classfile annotations</li> + * </ul> + */ + abstract class ClassfileAnnotArg + + /** Represents a compile-time Constant (Boolean, Byte, Short, + * Char, Int, Long, Float, Double, String, java.lang.Class or + * an instance of a Java enumeration value). + */ + case class LiteralAnnotArg(const: Constant) + extends ClassfileAnnotArg { + override def toString = const.escapedStringValue + } + + /** Represents an array of classfile annotation arguments */ + case class ArrayAnnotArg(args: Array[ClassfileAnnotArg]) + extends ClassfileAnnotArg { + override def toString = args.mkString("[", ", ", "]") + } + + /** A specific annotation argument that encodes an array of bytes as an array of `Long`. The type of the argument + * declared in the annotation must be `String`. This specialised class is used to encode scala signatures for + * reasons of efficiency, both in term of class-file size and in term of compiler performance. */ + case class ScalaSigBytes(bytes: Array[Byte]) extends ClassfileAnnotArg { + override def toString = (bytes map { byte => (byte & 0xff).toHexString }).mkString("[ ", " ", " ]") + lazy val encodedBytes = + reflect.generic.ByteCodecs.encode(bytes) + def isLong: Boolean = (encodedBytes.length > 65535) + def sigAnnot: Type = + if (this.isLong) + definitions.ScalaLongSignatureAnnotation.tpe + else + definitions.ScalaSignatureAnnotation.tpe + } + + /** Represents a nested classfile annotation */ + case class NestedAnnotArg(annInfo: AnnotationInfo) + extends ClassfileAnnotArg { + // The nested annotation should not have any Scala annotation arguments + assert(annInfo.args.isEmpty, annInfo.args) + override def toString = annInfo.toString + } + + class AnnotationInfoBase + + /** <p> + * Typed information about an annotation. It can be attached to + * either a symbol or an annotated type. + * </p> + * <p> + * Annotations are written to the classfile as java annotations + * if <code>atp</code> conforms to <code>ClassfileAnnotation</code> + * (the classfile parser adds this interface to any Java annotation + * class). + * </p> + * <p> + * Annotations are pickled (written to scala symtab attribute + * in the classfile) if <code>atp</code> inherits form + * <code>StaticAnnotation</code>. + * </p> + * <p> + * <code>args</code> stores arguments to Scala annotations, + * represented as typed trees. Note that these trees are not + * transformed by any phases following the type-checker. + * </p> + * <p> + * <code>assocs</code> stores arguments to classfile annotations + * as name-value pairs. + * </p> + */ + case class AnnotationInfo(atp: Type, args: List[Tree], + assocs: List[(Name, ClassfileAnnotArg)]) + extends AnnotationInfoBase { + + // Classfile annot: args empty. Scala annot: assocs empty. + assert(args.isEmpty || assocs.isEmpty) + + private var rawpos: Position = NoPosition + def pos = rawpos + def setPos(pos: Position): this.type = { + rawpos = pos + this + } + + lazy val isTrivial: Boolean = atp.isTrivial && !(args exists (_.exists(_.isInstanceOf[This]))) // see annotationArgRewriter + + override def toString: String = atp + + (if (!args.isEmpty) args.mkString("(", ", ", ")") else "") + + (if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "") + + /** Check whether the type or any of the arguments are erroneous */ + def isErroneous = atp.isErroneous || args.exists(_.isErroneous) + + /** Check whether any of the arguments mention a symbol */ + def refsSymbol(sym: Symbol) = + args.exists(_.exists(_.symbol == sym)) + + /** Change all ident's with Symbol "from" to instead use symbol "to" */ + def substIdentSyms(from: Symbol, to: Symbol) = { + val subs = new TreeSymSubstituter(List(from), List(to)) + AnnotationInfo(atp, args.map(subs(_)), assocs).setPos(pos) + } + + // !!! when annotation arguments are not literal strings, but any sort of + // assembly of strings, there is a fair chance they will turn up here not as + // Literal(const) but some arbitrary AST. + def stringArg(index: Int): Option[String] = if(args.size > index) Some(args(index) match { + case Literal(const) => const.stringValue + case x => x.toString // should not be necessary, but better than silently ignoring an issue + }) else None + + def intArg(index: Int): Option[Int] = if(args.size > index) Some(args(index)) collect { + case Literal(Constant(x: Int)) => x + } else None + } + + lazy val classfileAnnotArgManifest: ClassManifest[ClassfileAnnotArg] = + reflect.ClassManifest.classType(classOf[ClassfileAnnotArg]) + + /** Symbol annotations parsed in Namer (typeCompleter of + * definitions) have to be lazy (#1782) + */ + case class LazyAnnotationInfo(annot: () => AnnotationInfo) + extends AnnotationInfoBase +} diff --git a/src/compiler/scala/reflect/common/BaseTypeSeqs.scala b/src/compiler/scala/reflect/common/BaseTypeSeqs.scala new file mode 100644 index 0000000000..7a77ca8e62 --- /dev/null +++ b/src/compiler/scala/reflect/common/BaseTypeSeqs.scala @@ -0,0 +1,251 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ +package scala.reflect +package common + +// todo implement in terms of BitSet +import scala.collection.mutable.{ListBuffer, BitSet} +import math.max +import util.Statistics._ + +/** A base type sequence (BaseTypeSeq) is an ordered sequence spanning all the base types + * of a type. It characterized by the following two laws: + * + * (1) Each element of `tp.baseTypeSeq' is a basetype of `tp' + * (2) For each basetype `bt1' of `tp' there is an element `bt' in `tp.baseTypeSeq' such that + * + * bt.typeSymbol = bt1.typeSymbol + * bt <: bt1 + * + * (3) The type symbols of different elements are different. + * + * Elements in the sequence are ordered by Symbol.isLess. + * @note base type sequences were called closures up to 2.7.1. The name has been changed + * to avoid confusion with function closures. + */ +trait BaseTypeSeqs { + this: SymbolTable => + import definitions._ + + class BaseTypeSeq(parents: List[Type], elems: Array[Type]) { + self => + incCounter(baseTypeSeqCount) + incCounter(baseTypeSeqLenTotal, elems.length) + + /** The number of types in the sequence */ + def length: Int = elems.length + + // #3676 shows why we can't store NoType in elems to mark cycles + // (while NoType is in there to indicate a cycle in this BTS, during the execution of + // the mergePrefixAndArgs below, the elems get copied without the pending map, + // so that NoType's are seen instead of the original type --> spurious compile error) + val pending = new BitSet(length) + + /** The type at i'th position in this sequence; lazy types are returned evaluated. */ + def apply(i: Int): Type = + if(pending contains i) { + pending.clear() + throw CyclicInheritance + } else + elems(i) match { + case rtp @ RefinedType(variants, decls) => + // can't assert decls.isEmpty; see t0764 + //if (!decls.isEmpty) assert(false, "computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j)) + //Console.println("compute closure of "+this+" => glb("+variants+")") + pending += i + try { + mergePrefixAndArgs(variants, -1, lubDepth(variants)) match { + case Some(tp0) => + pending(i) = false + elems(i) = tp0 + tp0 + case None => + typeError( + "no common type instance of base types "+(variants mkString ", and ")+" exists.") + } + } catch { + case CyclicInheritance => + typeError( + "computing the common type instance of base types "+(variants mkString ", and ")+" leads to a cycle.") + } + case tp => + tp + } + + def rawElem(i: Int) = elems(i) + + /** The type symbol of the type at i'th position in this sequence; + * no evaluation needed. + */ + def typeSymbol(i: Int): Symbol = { + elems(i) match { + case RefinedType(v :: vs, _) => v.typeSymbol + case tp => tp.typeSymbol + } + } + + /** Return all evaluated types in this sequence as a list */ + def toList: List[Type] = elems.toList + + protected def copy(head: Type, offset: Int): BaseTypeSeq = { + val arr = new Array[Type](elems.length + offset) + compat.Platform.arraycopy(elems, 0, arr, offset, elems.length) + arr(0) = head + new BaseTypeSeq(parents, arr) + } + + /** Compute new base type sequence with `tp' prepended to this sequence */ + def prepend(tp: Type): BaseTypeSeq = copy(tp, 1) + + /** Compute new base type sequence with `tp' replacing the head of this sequence */ + def updateHead(tp: Type): BaseTypeSeq = copy(tp, 0) + + /** Compute new base type sequence where every element is mapped + * with function `f'. Lazy types are mapped but not evaluated */ + def map(f: Type => Type): BaseTypeSeq = { + // inlined `elems map f' for performance + val len = length + var arr = new Array[Type](len) + var i = 0 + while (i < len) { + arr(i) = f(elems(i)) + i += 1 + } + new BaseTypeSeq(parents, arr) + } + + def lateMap(f: Type => Type): BaseTypeSeq = new BaseTypeSeq(parents map f, elems) { + override def apply(i: Int) = f(self.apply(i)) + override def rawElem(i: Int) = f(self.rawElem(i)) + override def typeSymbol(i: Int) = self.typeSymbol(i) + override def toList = self.toList map f + override protected def copy(head: Type, offset: Int) = (self map f).copy(head, offset) + override def map(g: Type => Type) = lateMap(g) + override def lateMap(g: Type => Type) = self.lateMap(x => g(f(x))) + override def exists(p: Type => Boolean) = elems exists (x => p(f(x))) + override protected def maxDepthOfElems: Int = elems map (x => maxDpth(f(x))) max + override def toString = elems.mkString("MBTS(", ",", ")") + } + + def exists(p: Type => Boolean): Boolean = elems exists p + + lazy val maxDepth: Int = maxDepthOfElems + + protected def maxDepthOfElems = { + var d = 0 + for (i <- 0 until length) d = max(d, maxDpth(elems(i))) + d + } + + /** The maximum depth of type `tp' */ + protected def maxDpth(tp: Type): Int = tp match { + case TypeRef(pre, sym, args) => + max(maxDpth(pre), maxDpth(args) + 1) + case RefinedType(parents, decls) => + max(maxDpth(parents), maxDpth(decls.toList.map(_.info)) + 1) + case TypeBounds(lo, hi) => + max(maxDpth(lo), maxDpth(hi)) + case MethodType(paramtypes, result) => + maxDpth(result) + case NullaryMethodType(result) => + maxDpth(result) + case PolyType(tparams, result) => + max(maxDpth(result), maxDpth(tparams map (_.info)) + 1) + case ExistentialType(tparams, result) => + max(maxDpth(result), maxDpth(tparams map (_.info)) + 1) + case _ => + 1 + } + + /** The maximum depth of all types `tps' */ + private def maxDpth(tps: Seq[Type]): Int = { + var d = 0 + for (tp <- tps) d = max(d, maxDpth(tp)) + d + } + + override def toString = elems.mkString("BTS(", ",", ")") + + private def typeError(msg: String): Nothing = + throw new TypeError( + "the type intersection "+(parents mkString " with ")+" is malformed"+ + "\n --- because ---\n"+msg) + } + + /** A merker object for a base type sequence that's no yet computed. + * used to catch inheritance cycles + */ + val undetBaseTypeSeq: BaseTypeSeq = new BaseTypeSeq(List(), Array()) + + /** Create a base type sequence consisting of a single type */ + def baseTypeSingletonSeq(tp: Type): BaseTypeSeq = new BaseTypeSeq(List(), Array(tp)) + + /** Create the base type sequence of a compound type wuth given tp.parents */ + def compoundBaseTypeSeq(tp: Type): BaseTypeSeq = { + val tsym = tp.typeSymbol + val parents = tp.parents +// Console.println("computing baseTypeSeq of " + tsym.tpe + " " + parents)//DEBUG + val buf = new ListBuffer[Type] + buf += tsym.tpe + var btsSize = 1 + if (parents.nonEmpty) { + val nparents = parents.length + val pbtss = new Array[BaseTypeSeq](nparents) + val index = new Array[Int](nparents) + var i = 0 + for (p <- parents) { + pbtss(i) = + if (p.baseTypeSeq eq undetBaseTypeSeq) AnyClass.info.baseTypeSeq + else p.baseTypeSeq + index(i) = 0 + i += 1 + } + def nextTypeSymbol(i: Int): Symbol = { + val j = index(i) + val pbts = pbtss(i) + if (j < pbts.length) pbts.typeSymbol(j) else AnyClass + } + def nextRawElem(i: Int): Type = { + val j = index(i) + val pbts = pbtss(i) + if (j < pbts.length) pbts.rawElem(j) else AnyClass.tpe + } + var minSym: Symbol = NoSymbol + while (minSym != AnyClass) { + minSym = nextTypeSymbol(0) + i = 1 + while (i < nparents) { + val nextSym = nextTypeSymbol(i) + if (nextSym isLess minSym) + minSym = nextSym + i += 1 + } + var minTypes: List[Type] = List() + i = 0 + while (i < nparents) { + if (nextTypeSymbol(i) == minSym) { + nextRawElem(i) match { + case RefinedType(variants, decls) => + for (tp <- variants) + if (!(minTypes exists (tp =:=))) minTypes = tp :: minTypes + case tp => + if (!(minTypes exists (tp =:=))) minTypes = tp :: minTypes + } + index(i) = index(i) + 1 + } + i += 1 + } + buf += intersectionType(minTypes) + btsSize += 1 + } + } + val elems = new Array[Type](btsSize) + buf.copyToArray(elems, 0) +// Console.println("computed baseTypeSeq of " + tsym.tpe + " " + parents + ": "+elems.toString)//DEBUG + new BaseTypeSeq(parents, elems) + } + + val CyclicInheritance = new Throwable +} diff --git a/src/compiler/scala/reflect/common/Caches.scala b/src/compiler/scala/reflect/common/Caches.scala new file mode 100644 index 0000000000..2666761f92 --- /dev/null +++ b/src/compiler/scala/reflect/common/Caches.scala @@ -0,0 +1,103 @@ +/* NSC -- new scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.reflect +package common + +import scala.collection.{ mutable, immutable } + +/** A cache for some entity whose validity depends on a monotonically + * increasing sequence number. + */ +abstract class SequencedCache[T >: Null] { + def zero: Int + def sequenceId: Int + def calculate(): T + + /** If sequence numbers differ, this condition is consulted before + * updating the cached value. + */ + def isCacheValid: Boolean + + /** Public so accesses can be inlined. */ + @inline var cachedId: Int = 0 + @inline var cachedValue: T = _ + + /** Puts cache back in uninitialized state. */ + @inline final def clear() = { + cachedId = zero + cachedValue = null + } + /** Resets the sequence id without touching the cached value. */ + @inline final def reset() = { + cachedId = zero + } + + final def get(): T = { + if (cachedValue == null) { + cachedValue = calculate() + cachedId = sequenceId + } + else if (cachedId != sequenceId) { + if (!isCacheValid) + cachedValue = calculate() + + cachedId = sequenceId + } + cachedValue + } +} + +trait Caches { + self: SymbolTable => + + final def isValid(period: Period): Boolean = + period != 0 && runId(period) == currentRunId && { + val pid = phaseId(period) + if (phase.id > pid) infoTransformers.nextFrom(pid).pid >= phase.id + else infoTransformers.nextFrom(phase.id).pid >= pid + } + + final def isValidForBaseClasses(period: Period): Boolean = { + def noChangeInBaseClasses(it: InfoTransformer, limit: Phase#Id): Boolean = ( + it.pid >= limit || + !it.changesBaseClasses && noChangeInBaseClasses(it.next, limit) + ); + period != 0 && runId(period) == currentRunId && { + val pid = phaseId(period) + if (phase.id > pid) noChangeInBaseClasses(infoTransformers.nextFrom(pid), phase.id) + else noChangeInBaseClasses(infoTransformers.nextFrom(phase.id), pid) + } + } + + abstract class PeriodCache[T >: Null] extends SequencedCache[T] { + final val zero = NoPeriod + @inline final def sequenceId = currentPeriod + } + + abstract class ListOfTypesCache extends PeriodCache[List[Type]] { + @inline final def isCacheValid = isValidForBaseClasses(cachedId) + } + abstract class ListOfSymbolsCache extends PeriodCache[List[Symbol]] { + @inline final def isCacheValid = isValidForBaseClasses(cachedId) + } + abstract class BaseTypeSeqCache extends PeriodCache[BaseTypeSeq] { + @inline final def isCacheValid = isValidForBaseClasses(cachedId) + } + abstract class TypeCache extends PeriodCache[Type] { + @inline final def isCacheValid = isValid(cachedId) + } + abstract class TypeCacheForRunId extends SequencedCache[Type] { + final val zero = NoRunId + @inline final def sequenceId = currentRunId + @inline final override def isCacheValid = false + } + object TypeCache { + def apply(body: => Type): TypeCache = new TypeCache { + @inline final def calculate() = body + } + } +} + diff --git a/src/compiler/scala/reflect/common/ClassfileConstants.scala b/src/compiler/scala/reflect/common/ClassfileConstants.scala new file mode 100644 index 0000000000..a48b16be96 --- /dev/null +++ b/src/compiler/scala/reflect/common/ClassfileConstants.scala @@ -0,0 +1,332 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +object ClassfileConstants { + + final val JAVA_MAGIC = 0xCAFEBABE + final val JAVA_MAJOR_VERSION = 45 + final val JAVA_MINOR_VERSION = 3 + + /** <p> + * (see http://java.sun.com/docs/books/jvms/second_edition/jvms-clarify.html) + * </p> + * <p> + * If the <code>ACC_INTERFACE</code> flag is set, the <code>ACC_ABSTRACT</code> + * flag must also be set (ch. 2.13.1). + * </p> + * <p> + * A class file cannot have both its <code>ACC_FINAL</code> and + * <code>ACC_ABSTRACT</code> flags set (ch. 2.8.2). + * </p> + * <p> + * A field may have at most one of its <code>ACC_PRIVATE</code>, + * <code>ACC_PROTECTED</code>, <code>ACC_PUBLIC</code> flags set (ch. 2.7.4). + * </p> + * <p> + * A field may not have both its <code>ACC_FINAL</code> and + * <code>ACC_VOLATILE</code> flags set (ch. 2.9.1). + * </p> + * <p> + * If a method has its <code>ACC_ABSTRACT</code> flag set it must not + * have any of its <code>ACC_FINAL</code>, <code>ACC_NATIVE</code>, + * <code>ACC_PRIVATE</code>, <code>ACC_STATIC</code>, <code>ACC_STRICT</code>, + * or <code>ACC_SYNCHRONIZED</code> flags set (ch. 2.13.3.2). + * </p> + * <p> + * All interface methods must have their <code>ACC_ABSTRACT</code> and + * <code>ACC_PUBLIC</code> flags set. + * </p> + */ // Class Field Method + final val JAVA_ACC_PUBLIC = 0x0001 // X X X + final val JAVA_ACC_PRIVATE = 0x0002 // X X + final val JAVA_ACC_PROTECTED = 0x0004 // X X + final val JAVA_ACC_STATIC = 0x0008 // X X + final val JAVA_ACC_FINAL = 0x0010 // X X X + final val JAVA_ACC_SUPER = 0x0020 // X + final val JAVA_ACC_SYNCHRONIZED = 0x0020 // X + final val JAVA_ACC_VOLATILE = 0x0040 // X + final val JAVA_ACC_BRIDGE = 0x0040 // X + final val JAVA_ACC_TRANSIENT = 0x0080 // X + final val JAVA_ACC_VARARGS = 0x0080 // X + final val JAVA_ACC_NATIVE = 0x0100 // X + final val JAVA_ACC_INTERFACE = 0x0200 // X + final val JAVA_ACC_ABSTRACT = 0x0400 // X X + final val JAVA_ACC_STRICT = 0x0800 // X + final val JAVA_ACC_SYNTHETIC = 0x1000 // X X X + final val JAVA_ACC_ANNOTATION = 0x2000 // X + final val JAVA_ACC_ENUM = 0x4000 // X X + + // tags describing the type of a literal in the constant pool + final val CONSTANT_UTF8 = 1 + final val CONSTANT_UNICODE = 2 + final val CONSTANT_INTEGER = 3 + final val CONSTANT_FLOAT = 4 + final val CONSTANT_LONG = 5 + final val CONSTANT_DOUBLE = 6 + final val CONSTANT_CLASS = 7 + final val CONSTANT_STRING = 8 + final val CONSTANT_FIELDREF = 9 + final val CONSTANT_METHODREF = 10 + final val CONSTANT_INTFMETHODREF = 11 + final val CONSTANT_NAMEANDTYPE = 12 + + // tags describing the type of a literal in attribute values + final val BYTE_TAG = 'B' + final val CHAR_TAG = 'C' + final val DOUBLE_TAG = 'D' + final val FLOAT_TAG = 'F' + final val INT_TAG = 'I' + final val LONG_TAG = 'J' + final val SHORT_TAG = 'S' + final val BOOL_TAG = 'Z' + final val STRING_TAG = 's' + final val ENUM_TAG = 'e' + final val CLASS_TAG = 'c' + final val ARRAY_TAG = '[' + final val VOID_TAG = 'V' + final val TVAR_TAG = 'T' + final val ANNOTATION_TAG = '@' + final val SCALA_NOTHING = "scala.runtime.Nothing$" + final val SCALA_NULL = "scala.runtime.Null$" + + + // tags describing the type of newarray + final val T_BOOLEAN = 4 + final val T_CHAR = 5 + final val T_FLOAT = 6 + final val T_DOUBLE = 7 + final val T_BYTE = 8 + final val T_SHORT = 9 + final val T_INT = 10 + final val T_LONG = 11 + + // JVM mnemonics + final val nop = 0x00 + final val aconst_null = 0x01 + final val iconst_m1 = 0x02 + + final val iconst_0 = 0x03 + final val iconst_1 = 0x04 + final val iconst_2 = 0x05 + final val iconst_3 = 0x06 + final val iconst_4 = 0x07 + final val iconst_5 = 0x08 + + final val lconst_0 = 0x09 + final val lconst_1 = 0x0a + final val fconst_0 = 0x0b + final val fconst_1 = 0x0c + final val fconst_2 = 0x0d + final val dconst_0 = 0x0e + final val dconst_1 = 0x0f + + final val bipush = 0x10 + final val sipush = 0x11 + final val ldc = 0x12 + final val ldc_w = 0x13 + final val ldc2_w = 0x14 + + final val iload = 0x15 + final val lload = 0x16 + final val fload = 0x17 + final val dload = 0x18 + final val aload = 0x19 + + final val iload_0 = 0x1a + final val iload_1 = 0x1b + final val iload_2 = 0x1c + final val iload_3 = 0x1d + final val lload_0 = 0x1e + final val lload_1 = 0x1f + final val lload_2 = 0x20 + final val lload_3 = 0x21 + final val fload_0 = 0x22 + final val fload_1 = 0x23 + final val fload_2 = 0x24 + final val fload_3 = 0x25 + final val dload_0 = 0x26 + final val dload_1 = 0x27 + final val dload_2 = 0x28 + final val dload_3 = 0x29 + final val aload_0 = 0x2a + final val aload_1 = 0x2b + final val aload_2 = 0x2c + final val aload_3 = 0x2d + final val iaload = 0x2e + final val laload = 0x2f + final val faload = 0x30 + final val daload = 0x31 + final val aaload = 0x32 + final val baload = 0x33 + final val caload = 0x34 + final val saload = 0x35 + + final val istore = 0x36 + final val lstore = 0x37 + final val fstore = 0x38 + final val dstore = 0x39 + final val astore = 0x3a + final val istore_0 = 0x3b + final val istore_1 = 0x3c + final val istore_2 = 0x3d + final val istore_3 = 0x3e + final val lstore_0 = 0x3f + final val lstore_1 = 0x40 + final val lstore_2 = 0x41 + final val lstore_3 = 0x42 + final val fstore_0 = 0x43 + final val fstore_1 = 0x44 + final val fstore_2 = 0x45 + final val fstore_3 = 0x46 + final val dstore_0 = 0x47 + final val dstore_1 = 0x48 + final val dstore_2 = 0x49 + final val dstore_3 = 0x4a + final val astore_0 = 0x4b + final val astore_1 = 0x4c + final val astore_2 = 0x4d + final val astore_3 = 0x4e + final val iastore = 0x4f + final val lastore = 0x50 + final val fastore = 0x51 + final val dastore = 0x52 + final val aastore = 0x53 + final val bastore = 0x54 + final val castore = 0x55 + final val sastore = 0x56 + + final val pop = 0x57 + final val pop2 = 0x58 + final val dup = 0x59 + final val dup_x1 = 0x5a + final val dup_x2 = 0x5b + final val dup2 = 0x5c + final val dup2_x1 = 0x5d + final val dup2_x2 = 0x5e + final val swap = 0x5f + + final val iadd = 0x60 + final val ladd = 0x61 + final val fadd = 0x62 + final val dadd = 0x63 + final val isub = 0x64 + final val lsub = 0x65 + final val fsub = 0x66 + final val dsub = 0x67 + final val imul = 0x68 + final val lmul = 0x69 + final val fmul = 0x6a + final val dmul = 0x6b + final val idiv = 0x6c + final val ldiv = 0x6d + final val fdiv = 0x6e + final val ddiv = 0x6f + final val irem = 0x70 + final val lrem = 0x71 + final val frem = 0x72 + final val drem = 0x73 + + final val ineg = 0x74 + final val lneg = 0x75 + final val fneg = 0x76 + final val dneg = 0x77 + + final val ishl = 0x78 + final val lshl = 0x79 + final val ishr = 0x7a + final val lshr = 0x7b + final val iushr = 0x7c + final val lushr = 0x7d + final val iand = 0x7e + final val land = 0x7f + final val ior = 0x80 + final val lor = 0x81 + final val ixor = 0x82 + final val lxor = 0x83 + final val iinc = 0x84 + + final val i2l = 0x85 + final val i2f = 0x86 + final val i2d = 0x87 + final val l2i = 0x88 + final val l2f = 0x89 + final val l2d = 0x8a + final val f2i = 0x8b + final val f2l = 0x8c + final val f2d = 0x8d + final val d2i = 0x8e + final val d2l = 0x8f + final val d2f = 0x90 + final val i2b = 0x91 + final val i2c = 0x92 + final val i2s = 0x93 + + final val lcmp = 0x94 + final val fcmpl = 0x95 + final val fcmpg = 0x96 + final val dcmpl = 0x97 + final val dcmpg = 0x98 + + final val ifeq = 0x99 + final val ifne = 0x9a + final val iflt = 0x9b + final val ifge = 0x9c + final val ifgt = 0x9d + final val ifle = 0x9e + final val if_icmpeq = 0x9f + final val if_icmpne = 0xa0 + final val if_icmplt = 0xa1 + final val if_icmpge = 0xa2 + final val if_icmpgt = 0xa3 + final val if_icmple = 0xa4 + final val if_acmpeq = 0xa5 + final val if_acmpne = 0xa6 + final val goto = 0xa7 + final val jsr = 0xa8 + final val ret = 0xa9 + final val tableswitch = 0xaa + final val lookupswitch = 0xab + final val ireturn = 0xac + final val lreturn = 0xad + final val freturn = 0xae + final val dreturn = 0xaf + final val areturn = 0xb0 + final val return_ = 0xb1 + + final val getstatic = 0xb2 + final val putstatic = 0xb3 + final val getfield = 0xb4 + final val putfield = 0xb5 + + final val invokevirtual = 0xb6 + final val invokespecial = 0xb7 + final val invokestatic = 0xb8 + final val invokeinterface = 0xb9 + final val xxxunusedxxxx = 0xba + + final val new_ = 0xbb + final val newarray = 0xbc + final val anewarray = 0xbd + final val arraylength = 0xbe + final val athrow = 0xbf + final val checkcast = 0xc0 + final val instanceof = 0xc1 + final val monitorenter = 0xc2 + final val monitorexit = 0xc3 + final val wide = 0xc4 + final val multianewarray = 0xc5 + final val ifnull = 0xc6 + final val ifnonnull = 0xc7 + final val goto_w = 0xc8 + final val jsr_w = 0xc9 + + // reserved opcodes + final val breakpoint = 0xca + final val impdep1 = 0xfe + final val impdep2 = 0xff +} diff --git a/src/compiler/scala/reflect/common/Constants.scala b/src/compiler/scala/reflect/common/Constants.scala new file mode 100644 index 0000000000..6e96dae3e6 --- /dev/null +++ b/src/compiler/scala/reflect/common/Constants.scala @@ -0,0 +1,238 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +import java.lang.Integer.toOctalString +import annotation.switch + +trait Constants { + self: SymbolTable => + + import definitions._ + + final val NoTag = 0 + final val UnitTag = 1 + final val BooleanTag = 2 + final val ByteTag = 3 + final val ShortTag = 4 + final val CharTag = 5 + final val IntTag = 6 + final val LongTag = 7 + final val FloatTag = 8 + final val DoubleTag = 9 + final val StringTag = 10 + final val NullTag = 11 + final val ClassTag = 12 + // For supporting java enumerations inside java annotations (see ClassfileParser) + final val EnumTag = 13 + + case class Constant(value: Any) { + val tag: Int = value match { + case null => NullTag + case x: Unit => UnitTag + case x: Boolean => BooleanTag + case x: Byte => ByteTag + case x: Short => ShortTag + case x: Int => IntTag + case x: Long => LongTag + case x: Float => FloatTag + case x: Double => DoubleTag + case x: String => StringTag + case x: Char => CharTag + case x: Type => ClassTag + case x: Symbol => EnumTag + case _ => throw new Error("bad constant value: " + value) + } + + def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue + def isShortRange: Boolean = isIntRange && Short.MinValue <= intValue && intValue <= Short.MaxValue + def isCharRange: Boolean = isIntRange && Char.MinValue <= intValue && intValue <= Char.MaxValue + def isIntRange: Boolean = ByteTag <= tag && tag <= IntTag + def isLongRange: Boolean = ByteTag <= tag && tag <= LongTag + def isFloatRange: Boolean = ByteTag <= tag && tag <= FloatTag + def isNumeric: Boolean = ByteTag <= tag && tag <= DoubleTag + + def tpe: Type = tag match { + case UnitTag => UnitClass.tpe + case BooleanTag => BooleanClass.tpe + case ByteTag => ByteClass.tpe + case ShortTag => ShortClass.tpe + case CharTag => CharClass.tpe + case IntTag => IntClass.tpe + case LongTag => LongClass.tpe + case FloatTag => FloatClass.tpe + case DoubleTag => DoubleClass.tpe + case StringTag => StringClass.tpe + case NullTag => NullClass.tpe + case ClassTag => ClassType(value.asInstanceOf[Type]) + case EnumTag => + // given (in java): "class A { enum E { VAL1 } }" + // - symbolValue: the symbol of the actual enumeration value (VAL1) + // - .owner: the ModuleClasSymbol of the enumeration (object E) + // - .linkedClassOfClass: the ClassSymbol of the enumeration (class E) + symbolValue.owner.linkedClassOfClass.tpe + } + + /** We need the equals method to take account of tags as well as values. + */ + override def equals(other: Any): Boolean = other match { + case that: Constant => + this.tag == that.tag && + (this.value == that.value || this.isNaN && that.isNaN) + case _ => false + } + + def isNaN = value match { + case f: Float => f.isNaN + case d: Double => d.isNaN + case _ => false + } + + def booleanValue: Boolean = + if (tag == BooleanTag) value.asInstanceOf[Boolean] + else throw new Error("value " + value + " is not a boolean"); + + def byteValue: Byte = tag match { + case ByteTag => value.asInstanceOf[Byte] + case ShortTag => value.asInstanceOf[Short].toByte + case CharTag => value.asInstanceOf[Char].toByte + case IntTag => value.asInstanceOf[Int].toByte + case LongTag => value.asInstanceOf[Long].toByte + case FloatTag => value.asInstanceOf[Float].toByte + case DoubleTag => value.asInstanceOf[Double].toByte + case _ => throw new Error("value " + value + " is not a Byte") + } + + def shortValue: Short = tag match { + case ByteTag => value.asInstanceOf[Byte].toShort + case ShortTag => value.asInstanceOf[Short] + case CharTag => value.asInstanceOf[Char].toShort + case IntTag => value.asInstanceOf[Int].toShort + case LongTag => value.asInstanceOf[Long].toShort + case FloatTag => value.asInstanceOf[Float].toShort + case DoubleTag => value.asInstanceOf[Double].toShort + case _ => throw new Error("value " + value + " is not a Short") + } + + def charValue: Char = tag match { + case ByteTag => value.asInstanceOf[Byte].toChar + case ShortTag => value.asInstanceOf[Short].toChar + case CharTag => value.asInstanceOf[Char] + case IntTag => value.asInstanceOf[Int].toChar + case LongTag => value.asInstanceOf[Long].toChar + case FloatTag => value.asInstanceOf[Float].toChar + case DoubleTag => value.asInstanceOf[Double].toChar + case _ => throw new Error("value " + value + " is not a Char") + } + + def intValue: Int = tag match { + case ByteTag => value.asInstanceOf[Byte].toInt + case ShortTag => value.asInstanceOf[Short].toInt + case CharTag => value.asInstanceOf[Char].toInt + case IntTag => value.asInstanceOf[Int] + case LongTag => value.asInstanceOf[Long].toInt + case FloatTag => value.asInstanceOf[Float].toInt + case DoubleTag => value.asInstanceOf[Double].toInt + case _ => throw new Error("value " + value + " is not an Int") + } + + def longValue: Long = tag match { + case ByteTag => value.asInstanceOf[Byte].toLong + case ShortTag => value.asInstanceOf[Short].toLong + case CharTag => value.asInstanceOf[Char].toLong + case IntTag => value.asInstanceOf[Int].toLong + case LongTag => value.asInstanceOf[Long] + case FloatTag => value.asInstanceOf[Float].toLong + case DoubleTag => value.asInstanceOf[Double].toLong + case _ => throw new Error("value " + value + " is not a Long") + } + + def floatValue: Float = tag match { + case ByteTag => value.asInstanceOf[Byte].toFloat + case ShortTag => value.asInstanceOf[Short].toFloat + case CharTag => value.asInstanceOf[Char].toFloat + case IntTag => value.asInstanceOf[Int].toFloat + case LongTag => value.asInstanceOf[Long].toFloat + case FloatTag => value.asInstanceOf[Float] + case DoubleTag => value.asInstanceOf[Double].toFloat + case _ => throw new Error("value " + value + " is not a Float") + } + + def doubleValue: Double = tag match { + case ByteTag => value.asInstanceOf[Byte].toDouble + case ShortTag => value.asInstanceOf[Short].toDouble + case CharTag => value.asInstanceOf[Char].toDouble + case IntTag => value.asInstanceOf[Int].toDouble + case LongTag => value.asInstanceOf[Long].toDouble + case FloatTag => value.asInstanceOf[Float].toDouble + case DoubleTag => value.asInstanceOf[Double] + case _ => throw new Error("value " + value + " is not a Double") + } + + /** Convert constant value to conform to given type. + */ + def convertTo(pt: Type): Constant = { + val target = pt.typeSymbol + if (target == tpe.typeSymbol) + this + else if (target == ByteClass && isByteRange) + Constant(byteValue) + else if (target == ShortClass && isShortRange) + Constant(shortValue) + else if (target == CharClass && isCharRange) + Constant(charValue) + else if (target == IntClass && isIntRange) + Constant(intValue) + else if (target == LongClass && isLongRange) + Constant(longValue) + else if (target == FloatClass && isFloatRange) + Constant(floatValue) + else if (target == DoubleClass && isNumeric) + Constant(doubleValue) + else + null + } + + def stringValue: String = + if (value == null) "null" + else if (tag == ClassTag) signature(typeValue) + else value.toString() + + @switch def escapedChar(ch: Char): String = ch match { + case '\b' => "\\b" + case '\t' => "\\t" + case '\n' => "\\n" + case '\f' => "\\f" + case '\r' => "\\r" + case '"' => "\\\"" + case '\'' => "\\\'" + case '\\' => "\\\\" + case _ => String.valueOf(ch) + } + + def escapedStringValue: String = { + def escape(text: String): String = { + text map { ch => + if (ch.isControl) "\\0" + toOctalString(ch) + else escapedChar(ch) + } mkString "" + } + tag match { + case NullTag => "null" + case StringTag => "\"" + escape(stringValue) + "\"" + case ClassTag => "classOf[" + signature(typeValue) + "]" + case CharTag => escape("'" + escapedChar(charValue) + "'") + case LongTag => longValue.toString() + "L" + case _ => String.valueOf(value) + } + } + def typeValue: Type = value.asInstanceOf[Type] + def symbolValue: Symbol = value.asInstanceOf[Symbol] + + override def hashCode: Int = value.## * 41 + 17 + } +} diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/reflect/common/Definitions.scala index 6b419c629d..f2c4fc844e 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/reflect/common/Definitions.scala @@ -3,17 +3,15 @@ * @author Martin Odersky */ -package scala.tools.nsc -package symtab +package scala.reflect +package common import scala.collection.{ mutable, immutable } import scala.collection.mutable.{ HashMap } -import scala.tools.nsc.util.NoPosition import Flags._ import PartialFunction._ -import classfile.ClassfileConstants -trait Definitions extends reflect.generic.StandardDefinitions { +trait Definitions /*extends reflect.generic.StandardDefinitions*/ { self: SymbolTable => // the scala value classes @@ -117,7 +115,7 @@ trait Definitions extends reflect.generic.StandardDefinitions { ) } - object definitions extends AbsDefinitions with ValueClassDefinitions { + object definitions extends ValueClassDefinitions { private var isInitialized = false def isDefinitionsInitialized = isInitialized diff --git a/src/compiler/scala/reflect/common/Flags.scala b/src/compiler/scala/reflect/common/Flags.scala index 756ea3077b..8cdecd0da1 100644 --- a/src/compiler/scala/reflect/common/Flags.scala +++ b/src/compiler/scala/reflect/common/Flags.scala @@ -250,6 +250,8 @@ class Flags extends ModifierFlags { private final val PKL_MASK = 0x00000FFF + final val PickledFlags: Long = 0xFFFFFFFFL + private def rawPickledCorrespondence = Array( (IMPLICIT, IMPLICIT_PKL), (FINAL, FINAL_PKL), diff --git a/src/compiler/scala/reflect/common/HasFlags.scala b/src/compiler/scala/reflect/common/HasFlags.scala new file mode 100644 index 0000000000..cbdd20b122 --- /dev/null +++ b/src/compiler/scala/reflect/common/HasFlags.scala @@ -0,0 +1,231 @@ +package scala.reflect +package common + +/** ISSUE #1: Flag names vs. Test method names + * + * The following methods from Symbol have a name of + * the form isFoo where FOO is the name of a flag, but where the method + * body tests for more than whether the flag is set. + * + * There are two possibilities with such methods. Either the extra + * tests are strictly to partition among overloaded flags (which is + * the case we can live with in the short term, if each such flag's + * partitioning assumptions are documented) or they aren't. + * + * The second case implies that "x hasFlag FOO" and "x.isFoo" have + * different semantics, and this we can't live with, because even if + * we're smart enough to avoid being tripped up by that, the next guy isn't. + * + * No extreme measures necessary, only renaming isFoo to something + * which hews more closely to its implementation. (Or renaming the flag.) + * + // Defined in the compiler Symbol + // + final def isLabel = isMethod && !hasAccessorFlag && hasFlag(LABEL) + final def isLocal: Boolean = owner.isTerm + final def isModuleVar: Boolean = isVariable && hasFlag(MODULEVAR) + final def isStable = + isTerm && + !hasTraitFlag && + (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE)) && + !(tpe.isVolatile && !hasAnnotation(uncheckedStableClass)) + final def isStatic: Boolean = + hasFlag(STATIC) || isRoot || owner.isStaticOwner + override final def isTrait: Boolean = + isClass && hasFlag(TRAIT | notDEFERRED) // A virtual class becomes a trait (part of DEVIRTUALIZE) + + // Defined in the library Symbol + // + def isTrait: Boolean = isClass && hasFlag(TRAIT) // refined later for virtual classes. + final def isContravariant = isType && hasFlag(CONTRAVARIANT) + final def isCovariant = isType && hasFlag(COVARIANT) + final def isMethod = isTerm && hasFlag(METHOD) + final def isModule = isTerm && hasFlag(MODULE) + final def isPackage = isModule && hasFlag(PACKAGE) + * + */ + +/** ISSUE #2: Implicit flag relationships must be made explicit. + * + * For instance, every time the MODULE flag is set, the FINAL flag is + * set along with it: + * + .setFlag(FINAL | MODULE | PACKAGE | JAVA) + .setFlag(FINAL | MODULE | PACKAGE | JAVA).setInfo(rootLoader) + new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) + new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) + val m = new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) + setFlag(module.getFlag(ModuleToClassFlags) | MODULE | FINAL) + sourceModule.flags = MODULE | FINAL + + * However the same is not true of when the MODULE flag is cleared: + + sym.resetFlag(MODULE) + .setFlag(sym.flags | STABLE).resetFlag(MODULE) + sym.resetFlag(MODULE | FINAL | CASE) + + * It's not relevant whether this example poses any issues: we must + * not tolerate these uncertainties. If the flags are to move together + * then both setting and clearing have to be encapsulated. If there + * is a useful and used distinction between the various permutations + * of on and off, then it must be documented. It's the only way! + */ + +import Flags._ + +/** Common code utilized by Modifiers (which carry the flags associated + * with Trees) and Symbol. + */ +trait HasFlags { + type FlagsType + type AccessBoundaryType + type AnnotationType + + /** Though both Symbol and Modifiers widen this method to public, it's + * defined protected here to give us the option in the future to route + * flag methods through accessors and disallow raw flag manipulation. + * And after that, perhaps, on some magical day: a typesafe enumeration. + */ + protected def flags: FlagsType + + /** The printable representation of this entity's flags and access boundary, + * restricted to flags in the given mask. + */ + def hasFlagsToString(mask: FlagsType): String + + /** Access level encoding: there are three scala flags (PRIVATE, PROTECTED, + * and LOCAL) which combine with value privateWithin (the "foo" in private[foo]) + * to define from where an entity can be accessed. The meanings are as follows: + * + * PRIVATE access restricted to class only. + * PROTECTED access restricted to class and subclasses only. + * LOCAL can only be set in conjunction with PRIVATE or PROTECTED. + * Further restricts access to the same object instance. + * + * In addition, privateWithin can be used to set a visibility barrier. + * When set, everything contained in the named enclosing package or class + * has access. It is incompatible with PRIVATE or LOCAL, but is additive + * with PROTECTED (i.e. if either the flags or privateWithin allow access, + * then it is allowed.) + * + * The java access levels translate as follows: + * + * java private: hasFlag(PRIVATE) && !hasAccessBoundary + * java package: !hasFlag(PRIVATE | PROTECTED) && (privateWithin == enclosing package) + * java protected: hasFlag(PROTECTED) && (privateWithin == enclosing package) + * java public: !hasFlag(PRIVATE | PROTECTED) && !hasAccessBoundary + */ + def privateWithin: AccessBoundaryType + + /** A list of annotations attached to this entity. + */ + def annotations: List[AnnotationType] + + /** Whether this entity has a "privateWithin" visibility barrier attached. + */ + def hasAccessBoundary: Boolean + + /** Whether this entity has ANY of the flags in the given mask. + */ + def hasFlag(flag: Long): Boolean + + /** Whether this entity has ALL of the flags in the given mask. + */ + def hasAllFlags(mask: Long): Boolean + + /** Whether this entity has NONE of the flags in the given mask. + */ + def hasNoFlags(mask: Long): Boolean = !hasFlag(mask) + + // Tests which come through cleanly: both Symbol and Modifiers use these + // identically, testing for a single flag. + def isCase = hasFlag(CASE ) + def isFinal = hasFlag(FINAL ) + def isImplicit = hasFlag(IMPLICIT ) + def isLazy = hasFlag(LAZY ) + def isMutable = hasFlag(MUTABLE ) // in Modifiers, formerly isVariable + def isOverride = hasFlag(OVERRIDE ) + def isPrivate = hasFlag(PRIVATE ) + def isProtected = hasFlag(PROTECTED) + def isSynthetic = hasFlag(SYNTHETIC) + def isInterface = hasFlag(INTERFACE) + + // Newly introduced based on having a reasonably obvious clean translation. + def isPrivateLocal = hasAllFlags(PRIVATE | LOCAL) + def isProtectedLocal = hasAllFlags(PROTECTED | LOCAL) + def isParamAccessor = hasFlag(PARAMACCESSOR) + def isCaseAccessor = hasFlag(CASEACCESSOR) + def isSuperAccessor = hasFlag(SUPERACCESSOR) + def isLifted = hasFlag(LIFTED) + + // Formerly the Modifiers impl did not include the access boundary check, + // which must have been a bug. + def isPublic = hasNoFlags(PRIVATE | PROTECTED) && !hasAccessBoundary + + // Renamed the Modifiers impl from isArgument. + def isParameter = hasFlag(PARAM) + + // Removed isClass qualification since the flag isn't overloaded and + // sym.isClass is enforced in Namers#validate. + def isSealed = hasFlag(SEALED) + + // Removed !isClass qualification since the flag isn't overloaded. + def isDeferred = hasFlag(DEFERRED ) + + // Dropped isTerm condition because flag isn't overloaded. + def isAbstractOverride = hasFlag(ABSOVERRIDE) + + def isDefaultInit = hasFlag(DEFAULTINIT) + + // Disambiguating: DEFAULTPARAM, TRAIT + def hasDefault = hasAllFlags(DEFAULTPARAM | PARAM) + def isTrait = hasFlag(TRAIT) && !hasFlag(PARAM) + def hasTraitFlag = hasFlag(TRAIT) + def hasDefaultFlag = hasFlag(DEFAULTPARAM) + + // Straightforwardly named accessors already being used differently. + // These names are most likely temporary. + def hasAbstractFlag = hasFlag(ABSTRACT) + def hasAccessorFlag = hasFlag(ACCESSOR) + def hasLocalFlag = hasFlag(LOCAL) + def hasModuleFlag = hasFlag(MODULE) + def hasPackageFlag = hasFlag(PACKAGE) + def hasPreSuperFlag = hasFlag(PRESUPER) + def hasStableFlag = hasFlag(STABLE) + def hasStaticFlag = hasFlag(STATIC) + + // Disambiguating: BYNAMEPARAM, CAPTURED, COVARIANT. + def isByNameParam = hasAllFlags(BYNAMEPARAM | PARAM) + // Nope, these aren't going to fly: + // def isCapturedVariable = hasAllFlags(CAPTURED | MUTABLE) + // def isCovariant = hasFlag(COVARIANT) && hasNoFlags(PARAM | MUTABLE) + + // Disambiguating: LABEL, CONTRAVARIANT, INCONSTRUCTOR + def isLabel = hasAllFlags(LABEL | METHOD) && !hasAccessorFlag + // Cannot effectively disambiguate the others at this level. + def hasContravariantFlag = hasFlag(CONTRAVARIANT) + def hasInConstructorFlag = hasFlag(INCONSTRUCTOR) + + // Name + def isJavaDefined = hasFlag(JAVA) + + // Keeping some potentially ambiguous names around so as not to break + // the rest of the world + @deprecated("", "2.9.0") + def isAbstract = hasFlag(ABSTRACT) + // Problematic: + // ABSTRACT and DEFERRED too easy to confuse, and + // ABSTRACT + OVERRIDE ==> ABSOVERRIDE adds to it. + // + // final def isAbstractClass = isClass && hasFlag(ABSTRACT) + // def isAbstractType = false // to be overridden + + // Question: + // Which name? All other flags are isFlag so it's probably a mistake to + // vary from that, but isAccessor does sound like it includes the other + // *ACCESSOR flags. Perhaps something like isSimpleAccessor. + // + // def isAccessor = hasFlag(ACCESSOR ) + // final def isGetterOrSetter = hasAccessorFlag +} + diff --git a/src/compiler/scala/reflect/common/InfoTransformers.scala b/src/compiler/scala/reflect/common/InfoTransformers.scala new file mode 100644 index 0000000000..12fd57caee --- /dev/null +++ b/src/compiler/scala/reflect/common/InfoTransformers.scala @@ -0,0 +1,47 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +trait InfoTransformers { + self: SymbolTable => + + abstract class InfoTransformer { + var prev: InfoTransformer = this + var next: InfoTransformer = this + + val pid: Phase#Id + val changesBaseClasses: Boolean + def transform(sym: Symbol, tpe: Type): Type + + def insert(that: InfoTransformer) { + assert(this.pid != that.pid) + if (that.pid < this.pid) { + prev insert that + } else if (next.pid <= that.pid && next.pid != NoPhase.id) { + next insert that + } else { + that.next = next + that.prev = this + next.prev = that + this.next = that + } + } + + /** The InfoTransformer whose (pid == from). + * If no such exists, the InfoTransformer with the next + * higher pid. + */ + def nextFrom(from: Phase#Id): InfoTransformer = + if (from == this.pid) this + else if (from < this.pid) + if (prev.pid < from) this + else prev.nextFrom(from); + else if (next.pid == NoPhase.id) next + else next.nextFrom(from) + } +} + diff --git a/src/compiler/scala/reflect/common/NameManglers.scala b/src/compiler/scala/reflect/common/NameManglers.scala new file mode 100644 index 0000000000..2f603d36ed --- /dev/null +++ b/src/compiler/scala/reflect/common/NameManglers.scala @@ -0,0 +1,172 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +import java.security.MessageDigest +import scala.io.Codec +import Chars.isOperatorPart + +/** A trait to encapsulate name mangling. It's intended for the + * values and methods involved in assembling names out of other names, + * and not for simple synthetically named locals. + */ +trait NameManglers { + self: SymbolTable => + + trait NameManglingCommon { + self: CommonNames => + + def flattenedName(segments: Name*): NameType = compactedString(segments mkString "$") + + /** + * COMPACTIFY + * + * The hashed name has the form (prefix + marker + md5 + marker + suffix), where + * - prefix/suffix.length = MaxNameLength / 4 + * - md5.length = 32 + * + * We obtain the formula: + * + * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + 6 + * + * (+6 for ".class"). MaxNameLength can therefore be computed as follows: + */ + private final val marker = "$$$$" + private final val MaxNameLength = math.min( + settings.maxClassfileName.value - 6, + 2 * (settings.maxClassfileName.value - 6 - 2*marker.length - 32) + ) + private lazy val md5 = MessageDigest.getInstance("MD5") + private def toMD5(s: String, edge: Int) = { + val prefix = s take edge + val suffix = s takeRight edge + + val cs = s.toArray + val bytes = Codec toUTF8 cs + md5 update bytes + val md5chars = md5.digest() map (b => (b & 0xFF).toHexString) mkString + + prefix + marker + md5chars + marker + suffix + } + private def compactedString(s: String) = + if (s.length <= MaxNameLength) s + else toMD5(s, MaxNameLength / 4) + } + + trait TypeNameMangling extends NameManglingCommon { + self: tpnme.type => + + } + + trait TermNameMangling extends NameManglingCommon { + self: nme.type => + + val IMPL_CLASS_SUFFIX = "$class" + val SINGLETON_SUFFIX = ".type" + val LOCALDUMMY_PREFIX = "<local " // owner of local blocks + val PROTECTED_PREFIX = "protected$" + val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set" + val SELECTOR_DUMMY = "<unapply-selector>" + val SETTER_SUFFIX = encode("_=") + val SUPER_PREFIX_STRING = "super$" + val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$" + + def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR + def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX + /** !!! Foo$class$1 is an implClassName, I think. */ + def isImplClassName(name: Name) = name endsWith IMPL_CLASS_SUFFIX + def isLocalDummyName(name: Name) = name startsWith LOCALDUMMY_PREFIX + def isLocalName(name: Name) = name endsWith LOCAL_SUFFIX_STRING + def isLoopHeaderLabel(name: Name) = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) + def isProtectedAccessorName(name: Name) = name startsWith PROTECTED_PREFIX + def isReplWrapperName(name: Name) = name containsName INTERPRETER_IMPORT_WRAPPER + def isSetterName(name: Name) = name endsWith SETTER_SUFFIX + def isTraitSetterName(name: Name) = isSetterName(name) && (name containsName TRAIT_SETTER_SEPARATOR_STRING) + def isSingletonName(name: Name) = name endsWith SINGLETON_SUFFIX + + def isOpAssignmentName(name: Name) = name match { + case raw.NE | raw.LE | raw.GE | EMPTY => false + case _ => + name.endChar == '=' && name.startChar != '=' && isOperatorPart(name.startChar) + } + + /** The expanded setter name of `name' relative to this class `base` + */ + def expandedSetterName(name: TermName, base: Symbol): TermName = + expandedName(name, base, separator = TRAIT_SETTER_SEPARATOR_STRING) + + /** If `name' is an expandedName name, the original name. + * Otherwise `name' itself. + */ + def originalName(name: Name): Name = { + var i = name.length + while (i >= 2 && !(name(i - 1) == '$' && name(i - 2) == '$')) i -= 1 + if (i >= 2) { + while (i >= 3 && name(i - 3) == '$') i -= 1 + name.subName(i, name.length) + } else name + } + + /** Return the original name and the types on which this name + * is specialized. For example, + * {{{ + * splitSpecializedName("foo$mIcD$sp") == ('foo', "I", "D") + * }}} + * `foo$mIcD$sp` is the name of a method specialized on two type + * parameters, the first one belonging to the method itself, on Int, + * and another one belonging to the enclosing class, on Double. + */ + def splitSpecializedName(name: Name): (Name, String, String) = + if (name.endsWith("$sp")) { + val name1 = name stripEnd "$sp" + val idxC = name1 lastIndexOf 'c' + val idxM = name1 lastIndexOf 'm' + + (name1.subName(0, idxM - 1), + name1.subName(idxC + 1, name1.length).toString, + name1.subName(idxM + 1, idxC).toString) + } else + (name, "", "") + + def getterName(name: TermName): TermName = if (isLocalName(name)) localToGetter(name) else name + def getterToLocal(name: TermName): TermName = name.toTermName append LOCAL_SUFFIX_STRING + def getterToSetter(name: TermName): TermName = name.toTermName append SETTER_SUFFIX + def localToGetter(name: TermName): TermName = name stripEnd LOCAL_SUFFIX_STRING toTermName + + def setterToGetter(name: TermName): TermName = { + val p = name.pos(TRAIT_SETTER_SEPARATOR_STRING) + if (p < name.length) + setterToGetter(name.subName(p + TRAIT_SETTER_SEPARATOR_STRING.length, name.length)) + else + name stripEnd SETTER_SUFFIX toTermName + } + + def defaultGetterName(name: Name, pos: Int): TermName = { + val prefix = if (isConstructorName(name)) "init" else name + newTermName(prefix + DEFAULT_GETTER_STRING + pos) + } + def defaultGetterToMethod(name: Name): TermName = { + val p = name.pos(DEFAULT_GETTER_STRING) + if (p < name.length) name.subName(0, p) + else name + } + + def dropSingletonName(name: Name): TypeName = name stripEnd SINGLETON_SUFFIX toTypeName + def singletonName(name: Name): TypeName = name append SINGLETON_SUFFIX toTypeName + def implClassName(name: Name): TypeName = name append IMPL_CLASS_SUFFIX toTypeName + def interfaceName(implname: Name): TypeName = implname stripEnd IMPL_CLASS_SUFFIX toTypeName + def localDummyName(clazz: Symbol): TermName = newTermName(LOCALDUMMY_PREFIX + clazz.name + ">") + def productAccessorName(i: Int): TermName = newTermName("_" + i) + def superName(name: Name): TermName = newTermName(SUPER_PREFIX_STRING + name) + + /** The name of an accessor for protected symbols. */ + def protName(name: Name): TermName = newTermName(PROTECTED_PREFIX + name) + + /** The name of a setter for protected symbols. Used for inherited Java fields. */ + def protSetterName(name: Name): TermName = newTermName(PROTECTED_SET_PREFIX + name) + } +} diff --git a/src/compiler/scala/reflect/common/Names.scala b/src/compiler/scala/reflect/common/Names.scala new file mode 100644 index 0000000000..4122d7ba2d --- /dev/null +++ b/src/compiler/scala/reflect/common/Names.scala @@ -0,0 +1,434 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +import scala.reflect.NameTransformer +import scala.io.Codec +import java.security.MessageDigest + +/** The class Names ... + * + * @author Martin Odersky + * @version 1.0, 05/02/2005 + */ +trait Names /*extends reflect.generic.Names*/ { + +// Operations ------------------------------------------------------------- + + private final val HASH_SIZE = 0x8000 + private final val HASH_MASK = 0x7FFF + private final val NAME_SIZE = 0x20000 + + final val nameDebug = false + + /** memory to store all names sequentially + */ + var chrs: Array[Char] = new Array[Char](NAME_SIZE) + private var nc = 0 + + /** hashtable for finding term names quickly + */ + private val termHashtable = new Array[TermName](HASH_SIZE) + + /** hashtable for finding type names quickly + */ + private val typeHashtable = new Array[TypeName](HASH_SIZE) + + /** the hashcode of a name + */ + private def hashValue(cs: Array[Char], offset: Int, len: Int): Int = + if (len > 0) + (len * (41 * 41 * 41) + + cs(offset) * (41 * 41) + + cs(offset + len - 1) * 41 + + cs(offset + (len >> 1))) + else 0; + + /** Is (the ASCII representation of) name at given index equal to + * cs[offset..offset+len-1]? + */ + private def equals(index: Int, cs: Array[Char], offset: Int, len: Int): Boolean = { + var i = 0 + while ((i < len) && (chrs(index + i) == cs(offset + i))) + i += 1; + i == len + } + + /** enter characters into chrs array + */ + private def enterChars(cs: Array[Char], offset: Int, len: Int) { + var i = 0 + while (i < len) { + if (nc + i == chrs.length) { + val newchrs = new Array[Char](chrs.length * 2) + compat.Platform.arraycopy(chrs, 0, newchrs, 0, chrs.length) + chrs = newchrs + } + chrs(nc + i) = cs(offset + i) + i += 1 + } + if (len == 0) nc += 1 + else nc = nc + len + } + + /** Create a term name from the characters in cs[offset..offset+len-1]. + */ + def newTermName(cs: Array[Char], offset: Int, len: Int): TermName = { + val h = hashValue(cs, offset, len) & HASH_MASK + var n = termHashtable(h) + while ((n ne null) && (n.length != len || !equals(n.start, cs, offset, len))) + n = n.next; + if (n eq null) { + n = new TermName(nc, len, h) + enterChars(cs, offset, len) + } + n + } + + /** create a term name from string + */ + def newTermName(s: String): TermName = + newTermName(s.toCharArray(), 0, s.length()) + + /** Create a term name from the UTF8 encoded bytes in bs[offset..offset+len-1]. + */ + def newTermName(bs: Array[Byte], offset: Int, len: Int): TermName = + newTermName(Codec fromUTF8 bs.slice(offset, offset + len) mkString) + + /** Create a type name from the characters in cs[offset..offset+len-1]. + */ + def newTypeName(cs: Array[Char], offset: Int, len: Int): TypeName = + newTermName(cs, offset, len).toTypeName + + /** Create a type name from string + */ + def newTypeName(s: String): TypeName = + newTermName(s).toTypeName + + /** Create a type name from the UTF8 encoded bytes in bs[offset..offset+len-1]. + */ + def newTypeName(bs: Array[Byte], offset: Int, len: Int): TypeName = + newTermName(bs, offset, len).toTypeName + + def mkTermName(name: Name): TermName = name.toTermName + def mkTypeName(name: Name): TypeName = name.toTypeName + def isTermName(name: Name): Boolean = name.isTermName + def isTypeName(name: Name): Boolean = name.isTypeName + + def nameChars: Array[Char] = chrs + @deprecated("", "2.9.0") def view(s: String): TermName = newTermName(s) + + /** An implicit conversion from names to term names + */ + implicit def promoteTermNamesAsNecessary(name: Name): TermName = mkTermName(name) + + +// Classes ---------------------------------------------------------------------- + + /** The name class. */ + sealed abstract class Name(protected val index: Int, protected val len: Int) extends Function1[Int, Char] { + /** Index into name table */ + def start: Int = index + + /** next name in the same hash bucket + */ + def next: Name + + /** return the length of this name + */ + final def length: Int = len + final def isEmpty = length == 0 + final def nonEmpty = !isEmpty + + def isTermName: Boolean + def isTypeName: Boolean + def toTermName: TermName + def toTypeName: TypeName + def companionName: Name + def bothNames: List[Name] = List(toTermName, toTypeName) + + /** Copy bytes of this name to buffer cs, starting at position `offset`. + */ + final def copyChars(cs: Array[Char], offset: Int) = + compat.Platform.arraycopy(chrs, index, cs, offset, len) + + /** return the ascii representation of this name + */ + final def toChars: Array[Char] = { + val cs = new Array[Char](len) + copyChars(cs, 0) + cs + } + + /** return the string representation of this name + */ + final override def toString(): String = new String(chrs, index, len) + def debugString() = NameTransformer.decode(toString) + (if (isTypeName) "!" else "") + + /** Write to UTF8 representation of this name to given character array. + * Start copying to index `to'. Return index of next free byte in array. + * Array must have enough remaining space for all bytes + * (i.e. maximally 3*length bytes). + */ + final def copyUTF8(bs: Array[Byte], offset: Int): Int = { + val bytes = Codec toUTF8 chrs.slice(index, index + len) + compat.Platform.arraycopy(bytes, 0, bs, offset, bytes.length) + offset + bytes.length + } + + /** return the hash value of this name + */ + final override def hashCode(): Int = index + + // Presently disabled. + // override def equals(other: Any) = paranoidEquals(other) + private def paranoidEquals(other: Any): Boolean = { + val cmp = this eq other.asInstanceOf[AnyRef] + if (cmp || !nameDebug) + return cmp + + other match { + case x: String => + Console.println("Compared " + debugString + " and String '" + x + "'") + case x: Name => + if (this.isTermName != x.isTermName) { + val panic = this.toTermName == x.toTermName + Console.println("Compared '%s' and '%s', one term, one type.%s".format(this, x, + if (panic) " And they contain the same name string!" + else "" + )) + } + case _ => + } + false + } + + /** return the i'th Char of this name + */ + final def apply(i: Int): Char = chrs(index + i) + + /** return the index of first occurrence of char c in this name, length if not found */ + final def pos(c: Char): Int = pos(c, 0) + + /** return the index of first occurrence of char c in this name, length if not found */ + final def pos(s: String): Int = pos(s, 0) + + /** return the index of the first occurrence of character c in + * this name from start, length if not found. + * + * @param c the character + * @param start ... + * @return the index of the first occurrence of c + */ + final def pos(c: Char, start: Int): Int = { + var i = start + while (i < len && chrs(index + i) != c) i += 1 + i + } + + /** return the index of the first occurrence of nonempty string s + * in this name from start, length if not found. + * + * @param s the string + * @param start ... + * @return the index of the first occurrence of s + */ + final def pos(s: String, start: Int): Int = { + var i = pos(s.charAt(0), start) + while (i + s.length() <= len) { + var j = 1 + while (s.charAt(j) == chrs(index + i + j)) { + j += 1 + if (j == s.length()) return i + } + i = pos(s.charAt(0), i + 1) + } + len + } + + /** return the index of last occurrence of char c in this + * name, -1 if not found. + * + * @param c the character + * @return the index of the last occurrence of c + */ + final def lastPos(c: Char): Int = lastPos(c, len - 1) + + final def lastPos(s: String): Int = lastPos(s, len - s.length) + + /** return the index of the last occurrence of char c in this + * name from start, -1 if not found. + * + * @param c the character + * @param start ... + * @return the index of the last occurrence of c + */ + final def lastPos(c: Char, start: Int): Int = { + var i = start + while (i >= 0 && chrs(index + i) != c) i -= 1 + i + } + + /** return the index of the last occurrence of string s in this + * name from start, -1 if not found. + * + * @param s the string + * @param start ... + * @return the index of the last occurrence of s + */ + final def lastPos(s: String, start: Int): Int = { + var i = lastPos(s.charAt(0), start) + while (i >= 0) { + var j = 1; + while (s.charAt(j) == chrs(index + i + j)) { + j += 1 + if (j == s.length()) return i; + } + i = lastPos(s.charAt(0), i - 1) + } + -s.length() + } + + /** does this name start with prefix? + */ + final def startsWith(prefix: Name): Boolean = startsWith(prefix, 0) + + /** does this name start with prefix at given start index? + */ + final def startsWith(prefix: Name, start: Int): Boolean = { + var i = 0 + while (i < prefix.length && start + i < len && + chrs(index + start + i) == chrs(prefix.start + i)) + i += 1; + i == prefix.length + } + + /** does this name end with suffix? + */ + final def endsWith(suffix: Name): Boolean = endsWith(suffix, len) + + /** does this name end with suffix just before given end index? + */ + final def endsWith(suffix: Name, end: Int): Boolean = { + var i = 1 + while (i <= suffix.length && i <= end && + chrs(index + end - i) == chrs(suffix.start + suffix.length - i)) + i += 1; + i > suffix.length + } + + final def containsName(subname: String): Boolean = containsName(newTermName(subname)) + final def containsName(subname: Name): Boolean = { + var start = 0 + val last = len - subname.length + while (start <= last && !startsWith(subname, start)) start += 1 + start <= last + } + + /** Some thoroughly self-explanatory convenience functions. They + * assume that what they're being asked to do is known to be valid. + */ + final def startChar: Char = apply(0) + final def endChar: Char = apply(len - 1) + final def startsWith(char: Char): Boolean = len > 0 && startChar == char + final def startsWith(name: String): Boolean = startsWith(newTermName(name)) + final def endsWith(char: Char): Boolean = len > 0 && endChar == char + final def endsWith(name: String): Boolean = endsWith(newTermName(name)) + final def stripStart(prefix: Name): Name = subName(prefix.length, len) + final def stripStart(prefix: String): Name = subName(prefix.length, len) + final def stripEnd(suffix: Name): Name = subName(0, len - suffix.length) + final def stripEnd(suffix: String): Name = subName(0, len - suffix.length) + + def lastIndexOf(ch: Char) = toChars lastIndexOf ch + + /** Return the subname with characters from start to end-1. + */ + def subName(from: Int, to: Int): Name + + /** Replace all occurrences of `from` by `to` in + * name; result is always a term name. + */ + def replace(from: Char, to: Char): Name = { + val cs = new Array[Char](len) + var i = 0 + while (i < len) { + val ch = this(i) + cs(i) = if (ch == from) to else ch + i += 1 + } + newTermName(cs, 0, len) + } + + /** Replace operator symbols by corresponding $op_name. + */ + def encode: Name = { + val str = toString() + val res = NameTransformer.encode(str) + if (res == str) this + else if (isTypeName) newTypeName(res) + else newTermName(res) + } + + def append(suffix: String): Name + def append(suffix: Name): Name + + /** Replace $op_name by corresponding operator symbol. + */ + def decode: String = ( + NameTransformer.decode(toString()) + + (if (nameDebug && isTypeName) "!" else ""))//debug + + def isOperatorName: Boolean = decode != toString + def nameKind: String = if (isTypeName) "type" else "term" + def longString: String = nameKind + " " + NameTransformer.decode(toString) + } + + final class TermName(_index: Int, _len: Int, hash: Int) extends Name(_index, _len) { + var next: TermName = termHashtable(hash) + termHashtable(hash) = this + def isTermName: Boolean = true + def isTypeName: Boolean = false + def toTermName: TermName = this + def toTypeName: TypeName = { + val h = hashValue(chrs, index, len) & HASH_MASK + var n = typeHashtable(h) + while ((n ne null) && n.start != index) + n = n.next; + if (n eq null) + n = new TypeName(index, len, h); + n + } + def append(suffix: String): TermName = newTermName(this + suffix) + def append(suffix: Name): TermName = append(suffix.toString) + def companionName: TypeName = toTypeName + def subName(from: Int, to: Int): TermName = + newTermName(chrs, start + from, to - from) + } + + final class TypeName(_index: Int, _len: Int, hash: Int) extends Name(_index, _len) { + var next: TypeName = typeHashtable(hash) + typeHashtable(hash) = this + def isTermName: Boolean = false + def isTypeName: Boolean = true + def toTermName: TermName = { + val h = hashValue(chrs, index, len) & HASH_MASK + var n = termHashtable(h) + while ((n ne null) && n.start != index) + n = n.next; + if (n eq null) + n = new TermName(index, len, h); + n + } + def toTypeName: TypeName = this + + def append(suffix: String): TypeName = newTypeName(this + suffix) + def append(suffix: Name): TypeName = append(suffix.toString) + def companionName: TermName = toTermName + def subName(from: Int, to: Int): TypeName = + newTypeName(chrs, start + from, to - from) + } +} diff --git a/src/compiler/scala/reflect/common/Positions.scala b/src/compiler/scala/reflect/common/Positions.scala new file mode 100644 index 0000000000..e8048a65c9 --- /dev/null +++ b/src/compiler/scala/reflect/common/Positions.scala @@ -0,0 +1,33 @@ +package scala.reflect +package common + +trait Positions { self: SymbolTable => + + type Position + val NoPosition: Position + + def focusPos(pos: Position): Position + def isRangePos(pos: Position): Boolean + def showPos(pos: Position): String + + /** A position that wraps a set of trees. + * The point of the wrapping position is the point of the default position. + * If some of the trees are ranges, returns a range position enclosing all ranges + * Otherwise returns default position. + */ + def wrappingPos(default: Position, trees: List[Tree]): Position = default + + /** A position that wraps the non-empty set of trees. + * The point of the wrapping position is the point of the first trees' position. + * If all some the trees are non-synthetic, returns a range position enclosing the non-synthetic trees + * Otherwise returns a synthetic offset position to point. + */ + def wrappingPos(trees: List[Tree]): Position = trees.head.pos + + /** Ensure that given tree has no positions that overlap with + * any of the positions of `others`. This is done by + * shortening the range or assigning TransparentPositions + * to some of the nodes in `tree`. + */ + def ensureNonOverlapping(tree: Tree, others: List[Tree]) {} +}
\ No newline at end of file diff --git a/src/compiler/scala/reflect/common/Required.scala b/src/compiler/scala/reflect/common/Required.scala new file mode 100644 index 0000000000..a7d33fa8db --- /dev/null +++ b/src/compiler/scala/reflect/common/Required.scala @@ -0,0 +1,17 @@ +package scala.reflect +package common + +import settings.MutableSettings + +trait Required { self: SymbolTable => + + type AbstractFile >: Null <: { def path: String } + + def picklerPhase: Phase + + val treePrinter: TreePrinter + + val gen: TreeGen { val global: Required.this.type } + + def settings: MutableSettings +} diff --git a/src/compiler/scala/reflect/common/Scopes.scala b/src/compiler/scala/reflect/common/Scopes.scala new file mode 100644 index 0000000000..4fbfa1760e --- /dev/null +++ b/src/compiler/scala/reflect/common/Scopes.scala @@ -0,0 +1,326 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +trait Scopes { self: SymbolTable => + + class ScopeEntry(val sym: Symbol, val owner: Scope) { + /** the next entry in the hash bucket + */ + var tail: ScopeEntry = null + + /** the next entry in this scope + */ + var next: ScopeEntry = null + + override def hashCode(): Int = sym.name.start + override def toString(): String = sym.toString() + } + + /** + * @param sym ... + * @param owner ... + * @return ... + */ + private def newScopeEntry(sym: Symbol, owner: Scope): ScopeEntry = { + val e = new ScopeEntry(sym, owner) + e.next = owner.elems + owner.elems = e + e + } + + class Scope(initElems: ScopeEntry) extends Iterable[Symbol] { + + var elems: ScopeEntry = initElems + + /** The number of times this scope is nested in another + */ + private var nestinglevel = 0 + + /** the hash table + */ + private var hashtable: Array[ScopeEntry] = null + + /** a cache for all elements, to be used by symbol iterator. + */ + private var elemsCache: List[Symbol] = null + + /** size and mask of hash tables + * todo: make hashtables grow? + */ + private val HASHSIZE = 0x80 + private val HASHMASK = 0x7f + + /** the threshold number of entries from which a hashtable is constructed. + */ + private val MIN_HASH = 8 + + if (size >= MIN_HASH) createHash() + + def this() = this(null: ScopeEntry) + + def this(base: Scope) = { + this(base.elems) + nestinglevel = base.nestinglevel + 1 + } + + def this(decls: List[Symbol]) = { + this() + decls foreach enter + } + + /** Returns a new scope with the same content as this one. */ + def cloneScope: Scope = { + val clone = new Scope() + this.toList foreach (clone enter _) + clone + } + + /** is the scope empty? */ + override def isEmpty: Boolean = elems eq null + + /** the number of entries in this scope */ + override def size: Int = { + var s = 0 + var e = elems + while (e ne null) { + s += 1 + e = e.next + } + s + } + + /** enter a scope entry + * + * @param e ... + */ + def enter(e: ScopeEntry) { + elemsCache = null + if (hashtable ne null) { + val i = e.sym.name.start & HASHMASK + elems.tail = hashtable(i) + hashtable(i) = elems + } else if (size >= MIN_HASH) { + createHash() + } + } + + /** enter a symbol + * + * @param sym ... + */ + def enter(sym: Symbol): Symbol = { enter(newScopeEntry(sym, this)); sym } + + /** enter a symbol, asserting that no symbol with same name exists in scope + * + * @param sym ... + */ + def enterUnique(sym: Symbol) { + assert(lookup(sym.name) == NoSymbol) + enter(sym) + } + + private def createHash() { + hashtable = new Array[ScopeEntry](HASHSIZE) + enterInHash(elems) + } + + private def enterInHash(e: ScopeEntry) { + if (e ne null) { + enterInHash(e.next) + val i = e.sym.name.start & HASHMASK + e.tail = hashtable(i) + hashtable(i) = e + } + } + + def rehash(sym: Symbol, newname: Name) { + if (hashtable ne null) { + val index = sym.name.start & HASHMASK + var e1 = hashtable(index) + var e: ScopeEntry = null + if (e1 != null) { + if (e1.sym == sym) { + hashtable(index) = e1.tail + e = e1 + } else { + while (e1.tail != null && e1.tail.sym != sym) e1 = e1.tail + if (e1.tail != null) { + e = e1.tail + e1.tail = e.tail + } + } + } + if (e != null) { + val newindex = newname.start & HASHMASK + e.tail = hashtable(newindex) + hashtable(newindex) = e + } + } + } + + /** remove entry + * + * @param e ... + */ + def unlink(e: ScopeEntry) { + if (elems == e) { + elems = e.next + } else { + var e1 = elems + while (e1.next != e) e1 = e1.next + e1.next = e.next + } + if (hashtable ne null) { + val index = e.sym.name.start & HASHMASK + var e1 = hashtable(index) + if (e1 == e) { + hashtable(index) = e.tail + } else { + while (e1.tail != e) e1 = e1.tail; + e1.tail = e.tail + } + } + elemsCache = null + } + + /** remove symbol */ + def unlink(sym: Symbol) { + var e = lookupEntry(sym.name) + while (e ne null) { + if (e.sym == sym) unlink(e); + e = lookupNextEntry(e) + } + } + + /** lookup a symbol + * + * @param name ... + * @return ... + */ + def lookup(name: Name): Symbol = { + val e = lookupEntry(name) + if (e eq null) NoSymbol else e.sym + } + + /** Returns an iterator yielding every symbol with given name in this scope. + */ + def lookupAll(name: Name): Iterator[Symbol] = new Iterator[Symbol] { + var e = lookupEntry(name) + def hasNext: Boolean = e ne null + def next: Symbol = { val r = e.sym; e = lookupNextEntry(e); r } + } + + /** lookup a symbol entry matching given name. + * @note from Martin: I believe this is a hotspot or will be one + * in future versions of the type system. I have reverted the previous + * change to use iterators as too costly. + */ + def lookupEntry(name: Name): ScopeEntry = { + var e: ScopeEntry = null + if (hashtable ne null) { + e = hashtable(name.start & HASHMASK) + while ((e ne null) && e.sym.name != name) { + e = e.tail + } + } else { + e = elems + while ((e ne null) && e.sym.name != name) { + e = e.next + } + } + e + } + + /** lookup next entry with same name as this one + * @note from Martin: I believe this is a hotspot or will be one + * in future versions of the type system. I have reverted the previous + * change to use iterators as too costly. + */ + def lookupNextEntry(entry: ScopeEntry): ScopeEntry = { + var e = entry + if (hashtable ne null) + do { e = e.tail } while ((e ne null) && e.sym.name != entry.sym.name) + else + do { e = e.next } while ((e ne null) && e.sym.name != entry.sym.name); + e + } + + /** Return all symbols as a list in the order they were entered in this scope. + */ + override def toList: List[Symbol] = { + if (elemsCache eq null) { + elemsCache = Nil + var e = elems + while ((e ne null) && e.owner == this) { + elemsCache = e.sym :: elemsCache + e = e.next + } + } + elemsCache + } + + /** Return the nesting level of this scope, i.e. the number of times this scope + * was nested in another */ + def nestingLevel = nestinglevel + + /** Return all symbols as an iterator in the order they were entered in this scope. + */ + def iterator: Iterator[Symbol] = toList.iterator + +/* + /** Does this scope contain an entry for `sym`? + */ + def contains(sym: Symbol): Boolean = lookupAll(sym.name) contains sym + + /** A scope that contains all symbols of this scope and that also contains `sym`. + */ + def +(sym: Symbol): Scope = + if (contains(sym)) this + else { + val result = cloneScope + result enter sym + result + } + + /** A scope that contains all symbols of this scope except `sym`. + */ + def -(sym: Symbol): Scope = + if (!contains(sym)) this + else { + val result = cloneScope + result unlink sym + result + } +*/ + override def foreach[U](p: Symbol => U): Unit = toList foreach p + + override def filter(p: Symbol => Boolean): Scope = + if (!(toList forall p)) new Scope(toList filter p) else this + + override def mkString(start: String, sep: String, end: String) = + toList.map(_.defString).mkString(start, sep, end) + + override def toString(): String = mkString("Scope{\n ", ";\n ", "\n}") + + } + + def newScope: Scope = new Scope + + /** The empty scope (immutable). + */ + object EmptyScope extends Scope { + override def enter(e: ScopeEntry) { + abort("EmptyScope.enter") + } + } + + /** The error scope. + */ + class ErrorScope(owner: Symbol) extends Scope(null: ScopeEntry) +} + diff --git a/src/compiler/scala/reflect/common/StdNames.scala b/src/compiler/scala/reflect/common/StdNames.scala new file mode 100644 index 0000000000..5c1efa35ba --- /dev/null +++ b/src/compiler/scala/reflect/common/StdNames.scala @@ -0,0 +1,617 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +import scala.collection.immutable + +trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: SymbolTable => + + def encode(str: String): TermName = newTermName(NameTransformer.encode(str)) + + implicit def stringToTermName(s: String): TermName = newTermName(s) + + /** This should be the first trait in the linearization. */ + trait Keywords { + private var kws: Set[TermName] = Set() + private def kw(s: String): TermName = { + val result = newTermName(s) + kws = kws + result + result + } + + final val ABSTRACTkw: TermName = kw("abstract") + final val CASEkw: TermName = kw("case") + final val CLASSkw: TermName = kw("class") + final val CATCHkw: TermName = kw("catch") + final val DEFkw: TermName = kw("def") + final val DOkw: TermName = kw("do") + final val ELSEkw: TermName = kw("else") + final val EXTENDSkw: TermName = kw("extends") + final val FALSEkw: TermName = kw("false") + final val FINALkw: TermName = kw("final") + final val FINALLYkw: TermName = kw("finally") + final val FORkw: TermName = kw("for") + final val FORSOMEkw: TermName = kw("forSome") + final val IFkw: TermName = kw("if") + final val IMPLICITkw: TermName = kw("implicit") + final val IMPORTkw: TermName = kw("import") + final val LAZYkw: TermName = kw("lazy") + final val MATCHkw: TermName = kw("match") + final val NEWkw: TermName = kw("new") + final val NULLkw: TermName = kw("null") + final val OBJECTkw: TermName = kw("object") + final val OVERRIDEkw: TermName = kw("override") + final val PACKAGEkw: TermName = kw("package") + final val PRIVATEkw: TermName = kw("private") + final val PROTECTEDkw: TermName = kw("protected") + final val RETURNkw: TermName = kw("return") + final val SEALEDkw: TermName = kw("sealed") + final val SUPERkw: TermName = kw("super") + final val THISkw: TermName = kw("this") + final val THROWkw: TermName = kw("throw") + final val TRAITkw: TermName = kw("trait") + final val TRUEkw: TermName = kw("true") + final val TRYkw: TermName = kw("try") + final val TYPEkw: TermName = kw("type") + final val VALkw: TermName = kw("val") + final val VARkw: TermName = kw("var") + final val WITHkw: TermName = kw("with") + final val WHILEkw: TermName = kw("while") + final val YIELDkw: TermName = kw("yield") + final val DOTkw: TermName = kw(".") + final val USCOREkw: TermName = kw("_") + final val COLONkw: TermName = kw(":") + final val EQUALSkw: TermName = kw("=") + final val ARROWkw: TermName = kw("=>") + final val LARROWkw: TermName = kw("<-") + final val SUBTYPEkw: TermName = kw("<:") + final val VIEWBOUNDkw: TermName = kw("<%") + final val SUPERTYPEkw: TermName = kw(">:") + final val HASHkw: TermName = kw("#") + final val ATkw: TermName = kw("@") + + final val keywords = { + val result = kws.toSet + kws = null + result + } + + final val javaKeywords = new JavaKeywords() + } + + trait CommonNames /*extends LibraryCommonNames*/ { + + type NameType <: Name + implicit def createNameType(name: String): NameType + + val EMPTY: NameType = "" + val ANON_FUN_NAME: NameType = "$anonfun" + val EMPTY_PACKAGE_NAME: NameType = "<empty>" + val IMPORT: NameType = "<import>" + val MODULE_SUFFIX: NameType = "$module" + val ROOT: NameType = "<root>" + + // value types are all used as terms as well + final val Boolean: NameType = "Boolean" + final val Byte: NameType = "Byte" + final val Char: NameType = "Char" + final val Double: NameType = "Double" + final val Float: NameType = "Float" + final val Int: NameType = "Int" + final val Long: NameType = "Long" + final val Short: NameType = "Short" + final val Unit: NameType = "Unit" + + final val ScalaValueNames: scala.List[NameType] = + scala.List(Byte, Char, Short, Int, Long, Float, Double, Boolean, Unit) + + // types whose companions we utilize + final val Array: NameType = "Array" + final val List: NameType = "List" + final val Seq: NameType = "Seq" + final val Symbol: NameType = "Symbol" + + // fictions we use as both types and terms + final val ERROR: NameType = "<error>" + final val NO_NAME: NameType = "<none>" // formerly NOSYMBOL + final val WILDCARD: NameType = "_" + } + + trait TypeNames extends CommonNames { + final val BYNAME_PARAM_CLASS_NAME: NameType = "<byname>" + final val EQUALS_PATTERN_NAME: NameType = "<equals>" + final val JAVA_REPEATED_PARAM_CLASS_NAME: NameType = "<repeated...>" + final val LOCAL_CHILD: NameType = "<local child>" + final val REPEATED_PARAM_CLASS_NAME: NameType = "<repeated>" + final val WILDCARD_STAR: NameType = "_*" + + final val Any: NameType = "Any" + final val AnyRef: NameType = "AnyRef" + final val AnyVal: NameType = "AnyVal" + final val Nothing: NameType = "Nothing" + final val Null: NameType = "Null" + final val Object: NameType = "Object" + final val PartialFunction: NameType = "PartialFunction" + final val Product: NameType = "Product" + final val ScalaObject: NameType = "ScalaObject" + final val Serializable: NameType = "Serializable" + final val Singleton: NameType = "Singleton" + final val String: NameType = "String" + final val Throwable: NameType = "Throwable" + + // Annotation types + final val AnnotationDefaultATTR: NameType = "AnnotationDefault" + final val BridgeATTR: NameType = "Bridge" + final val ClassfileAnnotationATTR: NameType = "RuntimeInvisibleAnnotations" // RetentionPolicy.CLASS. Currently not used (Apr 2009). + final val CodeATTR: NameType = "Code" + final val ConstantValueATTR: NameType = "ConstantValue" + final val DeprecatedATTR: NameType = "Deprecated" + final val ExceptionsATTR: NameType = "Exceptions" + final val InnerClassesATTR: NameType = "InnerClasses" + final val JacoMetaATTR: NameType = "JacoMeta" + final val LineNumberTableATTR: NameType = "LineNumberTable" + final val LocalVariableTableATTR: NameType = "LocalVariableTable" + final val RuntimeAnnotationATTR: NameType = "RuntimeVisibleAnnotations" // RetentionPolicy.RUNTIME + final val RuntimeParamAnnotationATTR: NameType = "RuntimeVisibleParameterAnnotations" // RetentionPolicy.RUNTIME (annotations on parameters) + final val ScalaATTR: NameType = "Scala" + final val ScalaSignatureATTR: NameType = "ScalaSig" + final val SignatureATTR: NameType = "Signature" + final val SourceFileATTR: NameType = "SourceFile" + final val SyntheticATTR: NameType = "Synthetic" + } + + + trait TermNames extends Keywords with CommonNames { + // Compiler internal names + val ANYNAME: NameType = "<anyname>" + val CONSTRUCTOR: NameType = "<init>" + val FAKE_LOCAL_THIS: NameType = "this$" + val INITIALIZER: NameType = CONSTRUCTOR // Is this buying us something? + val MIXIN_CONSTRUCTOR: NameType = "$init$" + val MODULE_INSTANCE_FIELD: NameType = "MODULE$" + val OUTER: NameType = "$outer" + val OUTER_LOCAL: NameType = "$outer " // note the space + val SELF: NameType = "$this" + val SPECIALIZED_INSTANCE: NameType = "specInstance$" + val STAR: NameType = "*" + val THIS: NameType = "_$this" + + final val Nil: NameType = "Nil" + final val Predef: NameType = "Predef" + final val ScalaRunTime: NameType = "ScalaRunTime" + final val Some: NameType = "Some" + + // Compiler utilized names + // val productElementName: NameType = "productElementName" + val TYPE_ : NameType = "TYPE" + val add_ : NameType = "add" + val apply: NameType = "apply" + val arrayValue: NameType = "arrayValue" + val arraycopy: NameType = "arraycopy" + val asInstanceOf_ : NameType = "asInstanceOf" + val assert_ : NameType = "assert" + val assume_ : NameType = "assume" + val box: NameType = "box" + val bytes: NameType = "bytes" + val canEqual_ : NameType = "canEqual" + val checkInitialized: NameType = "checkInitialized" + val classOf: NameType = "classOf" + val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure + val conforms: NameType = "conforms" + val copy: NameType = "copy" + val delayedInit: NameType = "delayedInit" + val delayedInitArg: NameType = "delayedInit$body" + val drop: NameType = "drop" + val elem: NameType = "elem" + val eq: NameType = "eq" + val equals_ : NameType = if (forMSIL) "Equals" else "equals" + val error: NameType = "error" + val ex: NameType = "ex" + val false_ : NameType = "false" + val filter: NameType = "filter" + val finalize_ : NameType = if (forMSIL) "Finalize" else "finalize" + val find_ : NameType = "find" + val flatMap: NameType = "flatMap" + val foreach: NameType = "foreach" + val genericArrayOps: NameType = "genericArrayOps" + val get: NameType = "get" + val hasNext: NameType = "hasNext" + val hashCode_ : NameType = if (forMSIL) "GetHashCode" else "hashCode" + val hash_ : NameType = "hash" + val head: NameType = "head" + val identity: NameType = "identity" + val inlinedEquals: NameType = "inlinedEquals" + val applyDynamic: NameType = "applyDynamic" + val isArray: NameType = "isArray" + val isDefinedAt: NameType = "isDefinedAt" + val isEmpty: NameType = "isEmpty" + val isInstanceOf_ : NameType = "isInstanceOf" + val java: NameType = "java" + val lang: NameType = "lang" + val length: NameType = "length" + val lengthCompare: NameType = "lengthCompare" + val lift_ : NameType = "lift" + val main: NameType = "main" + val map: NameType = "map" + val ne: NameType = "ne" + val newArray: NameType = "newArray" + val next: NameType = "next" + val notifyAll_ : NameType = "notifyAll" + val notify_ : NameType = "notify" + val null_ : NameType = "null" + val ofDim: NameType = "ofDim" + val productArity: NameType = "productArity" + val productElement: NameType = "productElement" + val productPrefix: NameType = "productPrefix" + val readResolve: NameType = "readResolve" + val sameElements: NameType = "sameElements" + val scala_ : NameType = "scala" + val self: NameType = "self" + val setAccessible: NameType = "setAccessible" + val synchronized_ : NameType = "synchronized" + val tail: NameType = "tail" + val this_ : NameType = "this" + val throw_ : NameType = "throw" + val toArray: NameType = "toArray" + val toList: NameType = "toList" + val toSeq: NameType = "toSeq" + val toString_ : NameType = if (forMSIL) "ToString" else "toString" + val true_ : NameType = "true" + val unapply: NameType = "unapply" + val unapplySeq: NameType = "unapplySeq" + val unbox: NameType = "unbox" + val update: NameType = "update" + val value: NameType = "value" + val view_ : NameType = "view" + val wait_ : NameType = "wait" + val withFilter: NameType = "withFilter" + val wrapRefArray: NameType = "wrapRefArray" + val zip: NameType = "zip" + + // unencoded operators + object raw { + final val AMP : NameType = "&" + final val BANG : NameType = "!" + final val BAR : NameType = "|" + final val DOLLAR: NameType = "$" + final val GE: NameType = ">=" + final val LE: NameType = "<=" + final val MINUS: NameType = "-" + final val NE: NameType = "!=" + final val PLUS : NameType = "+" + final val SLASH: NameType = "/" + final val STAR : NameType = "*" + final val TILDE: NameType = "~" + + final val isUnary: Set[Name] = Set(MINUS, PLUS, TILDE, BANG) + } + + // value-conversion methods + val toByte: NameType = "toByte" + val toShort: NameType = "toShort" + val toChar: NameType = "toChar" + val toInt: NameType = "toInt" + val toLong: NameType = "toLong" + val toFloat: NameType = "toFloat" + val toDouble: NameType = "toDouble" + } + + object tpnme extends TypeNames /*with LibraryTypeNames*/ with TypeNameMangling { + type NameType = TypeName + implicit def createNameType(name: String): TypeName = newTypeName(name) + + val REFINE_CLASS_NAME: NameType = "<refinement>" + val ANON_CLASS_NAME: NameType = "$anon" + } + + val javanme = nme.javaKeywords + + object nme extends TermNames /*with LibraryTermNames*/ with TermNameMangling { + type NameType = TermName + def createNameType(name: String): TermName = newTermName(name) + + /** Translate a String into a list of simple TypeNames and TermNames. + * In all segments before the last, type/term is determined by whether + * the following separator char is '.' or '#'. In the last segment, + * the argument "assumeTerm" determines it. Examples: + * + * package foo { + * object Lorax { object Wog ; class Wog } + * class Lorax { object Zax ; class Zax } + * } + * + * f("foo.Lorax", true) == List("foo": Term, "Lorax": Term) // object Lorax + * f("foo.Lorax", false) == List("foo": Term, "Lorax": Type) // class Lorax + * f("Lorax.Wog", true) == List("Lorax": Term, "Wog": Term) // object Wog + * f("Lorax.Wog", false) == List("Lorax": Term, "Wog": Type) // class Wog + * f("Lorax#Zax", true) == List("Lorax": Type, "Zax": Term) // object Zax + * f("Lorax#Zax", false) == List("Lorax": Type, "Zax": Type) // class Zax + * + * Note that in actual scala syntax you cannot refer to object Zax without an + * instance of Lorax, so Lorax#Zax could only mean the type. One might think + * that Lorax#Zax.type would work, but this is not accepted by the parser. + * For the purposes of referencing that object, the syntax is allowed. + */ + def segments(name: String, assumeTerm: Boolean): List[Name] = { + def mkName(str: String, term: Boolean): Name = + if (term) newTermName(str) else newTypeName(str) + + name.indexWhere(ch => ch == '.' || ch == '#') match { + // it's the last segment: the parameter tells us whether type or term + case -1 => if (name == "") scala.Nil else scala.List(mkName(name, assumeTerm)) + // otherwise, we can tell based on whether '#' or '.' is the following char. + case idx => + val (simple, div, rest) = (name take idx, name charAt idx, name drop (idx + 1)) + mkName(simple, div == '.') :: segments(rest, assumeTerm) + } + } + private def bitmapName(n: Int, suffix: String): TermName = + newTermName(BITMAP_PREFIX + suffix + n) + + /** The name of bitmaps for initialized (public or protected) lazy vals. */ + def bitmapName(n: Int): TermName = bitmapName(n, "") + + /** The name of bitmaps for initialized transient lazy vals. */ + def bitmapNameForTransient(n: Int): TermName = bitmapName(n, "trans$") + + /** The name of bitmaps for initialized private lazy vals. */ + def bitmapNameForPrivate(n: Int): TermName = bitmapName(n, "priv$") + + /** The name of bitmaps for checkinit values */ + def bitmapNameForCheckinit(n: Int): TermName = bitmapName(n, "init$") + + /** The name of bitmaps for checkinit values that have transient flag*/ + def bitmapNameForCheckinitTransient(n: Int): TermName = bitmapName(n, "inittrans$") + + /** The expanded name of `name' relative to this class `base` with given `separator` + */ + def expandedName(name: TermName, base: Symbol, separator: String = EXPAND_SEPARATOR_STRING): TermName = + newTermName(base.fullName('$') + separator + name) + + def moduleVarName(name: TermName): TermName = newTermName("" + name + MODULE_SUFFIX) + + val EXPAND_SEPARATOR_STRING = "$$" + val LOCAL_SUFFIX_STRING = " " + val ROOTPKG: TermName = "_root_" + + /** Base strings from which synthetic names are derived. */ + val BITMAP_PREFIX = "bitmap$" + val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$" + val DEFAULT_GETTER_STRING = "$default$" + val DO_WHILE_PREFIX = "doWhile$" + val EQEQ_LOCAL_VAR = "eqEqTemp$" + val EVIDENCE_PARAM_PREFIX = "evidence$" + val EXCEPTION_RESULT_PREFIX = "exceptionResult" + val INTERPRETER_IMPORT_WRAPPER = "$iw" + val INTERPRETER_LINE_PREFIX = "line" + val INTERPRETER_SYNTHVAR_PREFIX = "synthvar$" + val INTERPRETER_VAR_PREFIX = "res" + val INTERPRETER_WRAPPER_SUFFIX = "$object" + val WHILE_PREFIX = "while$" + + def getCause = sn.GetCause + def getClass_ = sn.GetClass + def getMethod_ = sn.GetMethod + def invoke_ = sn.Invoke + + val ADD = encode("+") + val AND = encode("&") + val ASR = encode(">>") + val DIV = encode("/") + val EQ = encode("==") + val EQL = encode("=") + val GE = encode(">=") + val GT = encode(">") + val HASHHASH = encode("##") + val LE = encode("<=") + val LSL = encode("<<") + val LSR = encode(">>>") + val LT = encode("<") + val MINUS = encode("-") + val MOD = encode("%") + val MUL = encode("*") + val NE = encode("!=") + val OR = encode("|") + val PLUS = encode("+") + val SUB = encode("-") + val XOR = encode("^") + val ZAND = encode("&&") + val ZOR = encode("||") + + // unary operators + val UNARY_~ = encode("unary_~") + val UNARY_+ = encode("unary_+") + val UNARY_- = encode("unary_-") + val UNARY_! = encode("unary_!") + } + + abstract class SymbolNames { + protected implicit def stringToTypeName(s: String): TypeName = newTypeName(s) + + val BeanProperty : TypeName + val BooleanBeanProperty : TypeName + val BoxedBoolean : TypeName + val BoxedCharacter : TypeName + val BoxedNumber : TypeName + val Class : TypeName + val Code : TypeName + val Delegate : TypeName + val IOOBException : TypeName // IndexOutOfBoundsException + val InvTargetException : TypeName // InvocationTargetException + val JavaSerializable : TypeName + val MethodAsObject : TypeName + val NPException : TypeName // NullPointerException + val Object : TypeName + val String : TypeName + val Throwable : TypeName + val ValueType : TypeName + + val ForName : TermName + val GetCause : TermName + val GetClass : TermName + val GetMethod : TermName + val Invoke : TermName + val JavaLang : TermName + + val Boxed: immutable.Map[TypeName, TypeName] + } + + class JavaKeywords { + private var kws: Set[TermName] = Set() + private def kw(s: String): TermName = { + val result = newTermName(s) + kws = kws + result + result + } + + final val ABSTRACTkw: TermName = kw("abstract") + final val ASSERTkw: TermName = kw("assert") + final val BOOLEANkw: TermName = kw("boolean") + final val BREAKkw: TermName = kw("break") + final val BYTEkw: TermName = kw("byte") + final val CASEkw: TermName = kw("case") + final val CATCHkw: TermName = kw("catch") + final val CHARkw: TermName = kw("char") + final val CLASSkw: TermName = kw("class") + final val CONSTkw: TermName = kw("const") + final val CONTINUEkw: TermName = kw("continue") + final val DEFAULTkw: TermName = kw("default") + final val DOkw: TermName = kw("do") + final val DOUBLEkw: TermName = kw("double") + final val ELSEkw: TermName = kw("else") + final val ENUMkw: TermName = kw("enum") + final val EXTENDSkw: TermName = kw("extends") + final val FINALkw: TermName = kw("final") + final val FINALLYkw: TermName = kw("finally") + final val FLOATkw: TermName = kw("float") + final val FORkw: TermName = kw("for") + final val IFkw: TermName = kw("if") + final val GOTOkw: TermName = kw("goto") + final val IMPLEMENTSkw: TermName = kw("implements") + final val IMPORTkw: TermName = kw("import") + final val INSTANCEOFkw: TermName = kw("instanceof") + final val INTkw: TermName = kw("int") + final val INTERFACEkw: TermName = kw("interface") + final val LONGkw: TermName = kw("long") + final val NATIVEkw: TermName = kw("native") + final val NEWkw: TermName = kw("new") + final val PACKAGEkw: TermName = kw("package") + final val PRIVATEkw: TermName = kw("private") + final val PROTECTEDkw: TermName = kw("protected") + final val PUBLICkw: TermName = kw("public") + final val RETURNkw: TermName = kw("return") + final val SHORTkw: TermName = kw("short") + final val STATICkw: TermName = kw("static") + final val STRICTFPkw: TermName = kw("strictfp") + final val SUPERkw: TermName = kw("super") + final val SWITCHkw: TermName = kw("switch") + final val SYNCHRONIZEDkw: TermName = kw("synchronized") + final val THISkw: TermName = kw("this") + final val THROWkw: TermName = kw("throw") + final val THROWSkw: TermName = kw("throws") + final val TRANSIENTkw: TermName = kw("transient") + final val TRYkw: TermName = kw("try") + final val VOIDkw: TermName = kw("void") + final val VOLATILEkw: TermName = kw("volatile") + final val WHILEkw: TermName = kw("while") + + final val keywords = { + val result = kws.toSet + kws = null + result + } + } + + private abstract class JavaNames extends SymbolNames { + final val BoxedBoolean: TypeName = "java.lang.Boolean" + final val BoxedByte: TypeName = "java.lang.Byte" + final val BoxedCharacter: TypeName = "java.lang.Character" + final val BoxedDouble: TypeName = "java.lang.Double" + final val BoxedFloat: TypeName = "java.lang.Float" + final val BoxedInteger: TypeName = "java.lang.Integer" + final val BoxedLong: TypeName = "java.lang.Long" + final val BoxedNumber: TypeName = "java.lang.Number" + final val BoxedShort: TypeName = "java.lang.Short" + final val Class: TypeName = "java.lang.Class" + final val Delegate: TypeName = tpnme.NO_NAME + final val IOOBException: TypeName = "java.lang.IndexOutOfBoundsException" + final val InvTargetException: TypeName = "java.lang.reflect.InvocationTargetException" + final val MethodAsObject: TypeName = "java.lang.reflect.Method" + final val NPException: TypeName = "java.lang.NullPointerException" + final val Object: TypeName = "java.lang.Object" + final val String: TypeName = "java.lang.String" + final val Throwable: TypeName = "java.lang.Throwable" + final val ValueType: TypeName = tpnme.NO_NAME + + final val ForName: TermName = "forName" + final val GetCause: TermName = "getCause" + final val GetClass: TermName = "getClass" + final val GetMethod: TermName = "getMethod" + final val Invoke: TermName = "invoke" + final val JavaLang: TermName = "java.lang" + + val Boxed = immutable.Map[TypeName, TypeName]( + tpnme.Boolean -> BoxedBoolean, + tpnme.Byte -> BoxedByte, + tpnme.Char -> BoxedCharacter, + tpnme.Short -> BoxedShort, + tpnme.Int -> BoxedInteger, + tpnme.Long -> BoxedLong, + tpnme.Float -> BoxedFloat, + tpnme.Double -> BoxedDouble + ) + } + + private class MSILNames extends SymbolNames { + final val BeanProperty: TypeName = tpnme.NO_NAME + final val BooleanBeanProperty: TypeName = tpnme.NO_NAME + final val BoxedBoolean: TypeName = "System.IConvertible" + final val BoxedCharacter: TypeName = "System.IConvertible" + final val BoxedNumber: TypeName = "System.IConvertible" + final val Class: TypeName = "System.Type" + final val Code: TypeName = tpnme.NO_NAME + final val Delegate: TypeName = "System.MulticastDelegate" + final val IOOBException: TypeName = "System.IndexOutOfRangeException" + final val InvTargetException: TypeName = "System.Reflection.TargetInvocationException" + final val JavaSerializable: TypeName = tpnme.NO_NAME + final val MethodAsObject: TypeName = "System.Reflection.MethodInfo" + final val NPException: TypeName = "System.NullReferenceException" + final val Object: TypeName = "System.Object" + final val String: TypeName = "System.String" + final val Throwable: TypeName = "System.Exception" + final val ValueType: TypeName = "System.ValueType" + + final val ForName: TermName = "GetType" + final val GetCause: TermName = "InnerException" /* System.Reflection.TargetInvocationException.InnerException */ + final val GetClass: TermName = "GetType" + final val GetMethod: TermName = "GetMethod" + final val Invoke: TermName = "Invoke" + final val JavaLang: TermName = "System" + + val Boxed = immutable.Map[TypeName, TypeName]( + tpnme.Boolean -> "System.Boolean", + tpnme.Byte -> "System.SByte", // a scala.Byte is signed and a System.SByte too (unlike a System.Byte) + tpnme.Char -> "System.Char", + tpnme.Short -> "System.Int16", + tpnme.Int -> "System.Int32", + tpnme.Long -> "System.Int64", + tpnme.Float -> "System.Single", + tpnme.Double -> "System.Double" + ) + } + + private class J2SENames extends JavaNames { + final val BeanProperty: TypeName = "scala.reflect.BeanProperty" + final val BooleanBeanProperty: TypeName = "scala.reflect.BooleanBeanProperty" + final val Code: TypeName = "scala.reflect.Code" + final val JavaSerializable: TypeName = "java.io.Serializable" + } + + lazy val sn: SymbolNames = + if (forMSIL) new MSILNames + else new J2SENames +} diff --git a/src/compiler/scala/reflect/common/SymbolTable.scala b/src/compiler/scala/reflect/common/SymbolTable.scala new file mode 100644 index 0000000000..4bbe0b5201 --- /dev/null +++ b/src/compiler/scala/reflect/common/SymbolTable.scala @@ -0,0 +1,112 @@ +/* NSC -- new scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +import util._ + +abstract class SymbolTable extends /*reflect.generic.Universe + with*/ Names + with Symbols + with Types + with Scopes + with Caches + with Definitions + with Constants + with BaseTypeSeqs + with InfoTransformers + with StdNames + with AnnotationInfos + with AnnotationCheckers + with Trees + with TreePrinters + with Positions + with TypeDebugging + with Required +{ + def rootLoader: LazyType + def log(msg: => AnyRef) + def abort(msg: String): Nothing = throw new Error(msg) + def abort(): Nothing = throw new Error() + + /** Are we compiling for Java SE ? */ + // def forJVM: Boolean + + /** Are we compiling for .NET ? */ + def forMSIL: Boolean = false + + /** A period is an ordinal number for a phase in a run. + * Phases in later runs have higher periods than phases in earlier runs. + * Later phases have higher periods than earlier phases in the same run. + */ + type Period = Int + final val NoPeriod = 0 + + /** An ordinal number for compiler runs. First run has number 1. */ + type RunId = Int + final val NoRunId = 0 + + private var ph: Phase = NoPhase + private var per = NoPeriod + + final def phase: Phase = ph + + final def phase_=(p: Phase) { + //System.out.println("setting phase to " + p) + assert((p ne null) && p != NoPhase) + ph = p + per = (currentRunId << 8) + p.id + } + + /** The current compiler run identifier. */ + def currentRunId: RunId + + /** The run identifier of the given period */ + final def runId(period: Period): RunId = period >> 8 + + /** The phase identifier of the given period */ + final def phaseId(period: Period): Phase#Id = period & 0xFF + + /** The period at the start of run that includes `period' */ + final def startRun(period: Period): Period = period & 0xFFFFFF00 + + /** The current period */ + final def currentPeriod: Period = { + //assert(per == (currentRunId << 8) + phase.id) + per + } + + /** The phase associated with given period */ + final def phaseOf(period: Period): Phase = phaseWithId(phaseId(period)) + + final def period(rid: RunId, pid: Phase#Id): Period = + (currentRunId << 8) + pid + + /** Perform given operation at given phase */ + final def atPhase[T](ph: Phase)(op: => T): T = { + val current = phase + phase = ph + try op + finally phase = current + } + final def afterPhase[T](ph: Phase)(op: => T): T = + atPhase(ph.next)(op) + + /** Break into repl debugger if assertion is true */ + // def breakIf(assertion: => Boolean, args: Any*): Unit = + // if (assertion) + // ILoop.break(args.toList) + + /** The set of all installed infotransformers */ + var infoTransformers = new InfoTransformer { + val pid = NoPhase.id + val changesBaseClasses = true + def transform(sym: Symbol, tpe: Type): Type = tpe + } + + /** The phase which has given index as identifier */ + val phaseWithId: Array[Phase] +} diff --git a/src/compiler/scala/reflect/common/Symbols.scala b/src/compiler/scala/reflect/common/Symbols.scala new file mode 100644 index 0000000000..573871fa8b --- /dev/null +++ b/src/compiler/scala/reflect/common/Symbols.scala @@ -0,0 +1,2275 @@ + /* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + + +package scala.reflect +package common + +import scala.collection.{ mutable, immutable } +import scala.collection.mutable.ListBuffer +import util.Statistics._ +import Flags._ + +trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable => + import definitions._ + + private var ids = 0 + def symbolCount = ids // statistics + + val emptySymbolArray = new Array[Symbol](0) + + /** Used for deciding in the IDE whether we can interrupt the compiler */ + //protected var activeLocks = 0 + + /** Used for debugging only */ + //protected var lockedSyms = collection.immutable.Set[Symbol]() + + /** Used to keep track of the recursion depth on locked symbols */ + private var recursionTable = immutable.Map.empty[Symbol, Int] + + private var nextexid = 0 + private def freshExistentialName(suffix: String) = { + nextexid += 1 + newTypeName("_" + nextexid + suffix) + } + + /** The original owner of a class. Used by the backend to generate + * EnclosingMethod attributes. + */ + val originalOwner = mutable.HashMap[Symbol, Symbol]() + + /** The class for all symbols */ + abstract class Symbol(initOwner: Symbol, initPos: Position, initName: Name) extends HasFlags /*AbsSymbol */ { + + type FlagsType = Long + type AccessBoundaryType = Symbol + type AnnotationType = AnnotationInfo + + var rawowner = initOwner + var rawname = initName + var rawflags = 0L + + private var rawpos = initPos + val id = { ids += 1; ids } // identity displayed when -uniqid + + var validTo: Period = NoPeriod + + def pos = rawpos + def setPos(pos: Position): this.type = { this.rawpos = pos; this } + +// ------ creators ------------------------------------------------------------------- + + final def newValue(pos: Position, name: TermName) = + new TermSymbol(this, pos, name) + final def newValue(name: TermName, pos: Position = NoPosition) = + new TermSymbol(this, pos, name) + final def newVariable(pos: Position, name: TermName) = + newValue(pos, name).setFlag(MUTABLE) + final def newValueParameter(pos: Position, name: TermName) = + newValue(pos, name).setFlag(PARAM) + /** Create local dummy for template (owner of local blocks) */ + final def newLocalDummy(pos: Position) = + newValue(pos, nme.localDummyName(this)).setInfo(NoType) + final def newMethod(pos: Position, name: TermName) = + new MethodSymbol(this, pos, name).setFlag(METHOD) + final def newMethod(name: TermName, pos: Position = NoPosition) = + new MethodSymbol(this, pos, name).setFlag(METHOD) + final def newLabel(pos: Position, name: TermName) = + newMethod(pos, name).setFlag(LABEL) + final def newConstructor(pos: Position) = + newMethod(pos, nme.CONSTRUCTOR) + final def newModule(pos: Position, name: TermName, clazz: ClassSymbol) = + new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) + .setModuleClass(clazz) + final def newModule(name: TermName, clazz: Symbol, pos: Position = NoPosition) = + new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) + .setModuleClass(clazz.asInstanceOf[ClassSymbol]) + final def newModule(pos: Position, name: TermName) = { + val m = new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) + m.setModuleClass(new ModuleClassSymbol(m)) + } + final def newPackage(pos: Position, name: TermName) = { + assert(name == nme.ROOT || isPackageClass) + val m = newModule(pos, name).setFlag(JAVA | PACKAGE) + m.moduleClass.setFlag(JAVA | PACKAGE) + m + } + final def newThisSym(pos: Position) = + newValue(pos, nme.this_).setFlag(SYNTHETIC) + final def newImport(pos: Position) = + newValue(pos, nme.IMPORT) + + /** @param pre type relative to which alternatives are seen. + * for instance: + * class C[T] { + * def m(x: T): T + * def m'(): T + * } + * val v: C[Int] + * + * Then v.m has symbol TermSymbol(flags = {OVERLOADED}, + * tpe = OverloadedType(C[Int], List(m, m'))) + * You recover the type of m doing a + * + * m.tpe.asSeenFrom(pre, C) (generally, owner of m, which is C here). + * + * or: + * + * pre.memberType(m) + */ + final def newOverloaded(pre: Type, alternatives: List[Symbol]): Symbol = + newValue(alternatives.head.pos, alternatives.head.name.toTermName) + .setFlag(OVERLOADED) + .setInfo(OverloadedType(pre, alternatives)) + + /** for explicit outer phase */ + final def newOuterAccessor(pos: Position) = { + val sym = newMethod(pos, nme.OUTER) + sym setFlag (STABLE | SYNTHETIC) + if (isTrait) sym setFlag DEFERRED + sym.expandName(this) + sym.referenced = this + sym + } + + final def newErrorValue(name: TermName) = + newValue(pos, name).setFlag(SYNTHETIC | IS_ERROR).setInfo(ErrorType) + + /** Symbol of a type definition type T = ... + */ + final def newAliasType(pos: Position, name: TypeName) = + new TypeSymbol(this, pos, name) + final def newAliasType(name: TypeName, pos: Position = NoPosition) = + new TypeSymbol(this, pos, name) + + /** Symbol of an abstract type type T >: ... <: ... + */ + final def newAbstractType(pos: Position, name: TypeName) = + new TypeSymbol(this, pos, name).setFlag(DEFERRED) + final def newAbstractType(name: TypeName, pos: Position = NoPosition) = + new TypeSymbol(this, pos, name).setFlag(DEFERRED) + + /** Symbol of a type parameter + */ + final def newTypeParameter(pos: Position, name: TypeName) = + newAbstractType(pos, name).setFlag(PARAM) + + /** Synthetic value parameters when parameter symbols are not available + */ + final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[Symbol]] = { + var cnt = 0 + def freshName() = { cnt += 1; newTermName("x$" + cnt) } + def param(tp: Type) = + newValueParameter(focusPos(owner.pos), freshName()).setFlag(SYNTHETIC).setInfo(tp) + argtypess map (_.map(param)) + } + + final def newExistential(pos: Position, name: TypeName): Symbol = + newAbstractType(pos, name).setFlag(EXISTENTIAL) + + final def freshExistential(suffix: String): Symbol = + newExistential(pos, freshExistentialName(suffix)) + + /** Synthetic value parameters when parameter symbols are not available. + * Calling this method multiple times will re-use the same parameter names. + */ + final def newSyntheticValueParams(argtypes: List[Type]): List[Symbol] = + newSyntheticValueParamss(List(argtypes)).head + + /** Synthetic value parameter when parameter symbol is not available. + * Calling this method multiple times will re-use the same parameter name. + */ + final def newSyntheticValueParam(argtype: Type): Symbol = + newSyntheticValueParams(List(argtype)).head + + /** Type skolems are type parameters ``seen from the inside'' + * Assuming a polymorphic method m[T], its type is a PolyType which has a TypeParameter + * with name `T' in its typeParams list. While type checking the parameters, result type and + * body of the method, there's a local copy of `T' which is a TypeSkolem. + */ + final def newTypeSkolem: Symbol = + new TypeSkolem(owner, pos, name.toTypeName, this) + .setFlag(flags) + + final def newClass(pos: Position, name: TypeName) = + new ClassSymbol(this, pos, name) + final def newClass(name: TypeName, pos: Position = NoPosition) = + new ClassSymbol(this, pos, name) + + final def newModuleClass(pos: Position, name: TypeName) = + new ModuleClassSymbol(this, pos, name) + final def newModuleClass(name: TypeName, pos: Position = NoPosition) = + new ModuleClassSymbol(this, pos, name) + + final def newAnonymousClass(pos: Position) = + newClass(pos, tpnme.ANON_CLASS_NAME) + final def newAnonymousFunctionClass(pos: Position) = + newClass(pos, tpnme.ANON_FUN_NAME) + + /** Refinement types P { val x: String; type T <: Number } + * also have symbols, they are refinementClasses + */ + final def newRefinementClass(pos: Position) = + newClass(pos, tpnme.REFINE_CLASS_NAME) + + /** Create a new getter for current symbol (which must be a field) + */ + final def newGetter: Symbol = { + val getter = owner.newMethod(focusPos(pos), nme.getterName(name)).setFlag(getterFlags(flags)) + getter.privateWithin = privateWithin + getter.setInfo(MethodType(List(), tpe)) + } + + final def newErrorClass(name: TypeName) = { + val clazz = newClass(pos, name).setFlag(SYNTHETIC | IS_ERROR) + clazz.setInfo(ClassInfoType(List(), new ErrorScope(this), clazz)) + clazz + } + + final def newErrorSymbol(name: Name): Symbol = name match { + case x: TypeName => newErrorClass(x) + case x: TermName => newErrorValue(x) + } + +// ----- locking and unlocking ------------------------------------------------------ + + // True if the symbol is unlocked. + // True if the symbol is locked but still below the allowed recursion depth. + // False otherwise + def lockOK: Boolean = { + ((rawflags & LOCKED) == 0L) || + ((settings.Yrecursion.value != 0) && + (recursionTable get this match { + case Some(n) => (n <= settings.Yrecursion.value) + case None => true })) + } + + // Lock a symbol, using the handler if the recursion depth becomes too great. + def lock(handler: => Unit) = { + if ((rawflags & LOCKED) != 0L) { + if (settings.Yrecursion.value != 0) { + recursionTable get this match { + case Some(n) => + if (n > settings.Yrecursion.value) { + handler + } else { + recursionTable += (this -> (n + 1)) + } + case None => + recursionTable += (this -> 1) + } + } else { handler } + } else { + rawflags |= LOCKED +// activeLocks += 1 +// lockedSyms += this + } + } + + // Unlock a symbol + def unlock() = { + if ((rawflags & LOCKED) != 0L) { +// activeLocks -= 1 +// lockedSyms -= this + rawflags = rawflags & ~LOCKED + if (settings.Yrecursion.value != 0) + recursionTable -= this + } + } + +// ----- tests ---------------------------------------------------------------------- + + def isTerm = false // to be overridden + def isType = false // to be overridden + def isClass = false // to be overridden + def isAliasType = false // to be overridden + def isAbstractType = false // to be overridden + private[scala] def isSkolem = false // to be overridden + + /** Is this symbol a type but not a class? */ + def isNonClassType = false // to be overridden + + override final def isTrait: Boolean = isClass && hasFlag(TRAIT | notDEFERRED) // A virtual class becomes a trait (part of DEVIRTUALIZE) + final def isAbstractClass = isClass && hasFlag(ABSTRACT) + final def isBridge = hasFlag(BRIDGE) + final def isContravariant = isType && hasFlag(CONTRAVARIANT) + final def isCovariant = isType && hasFlag(COVARIANT) + final def isEarlyInitialized: Boolean = isTerm && hasFlag(PRESUPER) + final def isExistentiallyBound = isType && hasFlag(EXISTENTIAL) + final def isImplClass = isClass && hasFlag(IMPLCLASS) // Is this symbol an implementation class for a mixin? + final def isLazyAccessor = isLazy && lazyAccessor != NoSymbol + final def isMethod = isTerm && hasFlag(METHOD) + final def isVarargsMethod = isMethod && hasFlag(VARARGS) + final def isModule = isTerm && hasFlag(MODULE) + final def isModuleClass = isClass && hasFlag(MODULE) + final def isOverloaded = hasFlag(OVERLOADED) + final def isRefinementClass = isClass && name == tpnme.REFINE_CLASS_NAME + final def isSourceMethod = isMethod && !hasFlag(STABLE) // exclude all accessors!!! + final def isTypeParameter = isType && isParameter && !isSkolem + + /** Package tests */ + final def isEmptyPackage = isPackage && name == nme.EMPTY_PACKAGE_NAME + final def isEmptyPackageClass = isPackageClass && name == tpnme.EMPTY_PACKAGE_NAME + final def isPackage = isModule && hasFlag(PACKAGE) + final def isPackageClass = isClass && hasFlag(PACKAGE) + final def isRoot = isPackageClass && owner == NoSymbol + final def isRootPackage = isPackage && owner == NoSymbol + + /** Does this symbol denote a wrapper created by the repl? */ + final def isInterpreterWrapper = (isModule || isModuleClass) && nme.isReplWrapperName(name) + + /** Is this symbol an effective root for fullname string? + */ + def isEffectiveRoot = isRoot || isEmptyPackageClass || isInterpreterWrapper + + /** Term symbols with the exception of static parts of Java classes and packages. + */ + final def isValue = isTerm && !(isModule && hasFlag(PACKAGE | JAVA)) + + final def isVariable = isTerm && isMutable && !isMethod + + // interesting only for lambda lift. Captured variables are accessed from inner lambdas. + final def isCapturedVariable = isVariable && hasFlag(CAPTURED) + + final def isGetter = isTerm && hasAccessorFlag && !nme.isSetterName(name) + // todo: make independent of name, as this can be forged. + final def isSetter = isTerm && hasAccessorFlag && nme.isSetterName(name) + def isSetterParameter = isValueParameter && owner.isSetter + + final def hasGetter = isTerm && nme.isLocalName(name) + + final def isValueParameter = isTerm && hasFlag(PARAM) + final def isLocalDummy = isTerm && nme.isLocalDummyName(name) + final def isInitializedToDefault = !isType && hasAllFlags(DEFAULTINIT | ACCESSOR) + final def isClassConstructor = isTerm && (name == nme.CONSTRUCTOR) + final def isMixinConstructor = isTerm && (name == nme.MIXIN_CONSTRUCTOR) + final def isConstructor = isTerm && nme.isConstructorName(name) + final def isStaticModule = isModule && isStatic && !isMethod + final def isThisSym = isTerm && owner.thisSym == this + final def isError = hasFlag(IS_ERROR) + final def isErroneous = isError || isInitialized && tpe.isErroneous + final def isTypeParameterOrSkolem = isType && hasFlag(PARAM) + final def isHigherOrderTypeParameter = owner.isTypeParameterOrSkolem + final def isTypeSkolem = isSkolem && hasFlag(PARAM) + // a type symbol bound by an existential type, for instance the T in + // List[T] forSome { type T } + final def isExistentialSkolem = isExistentiallyBound && isSkolem + final def isExistentialQuantified = isExistentiallyBound && !isSkolem + + // class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor + final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR) + + final def isAnonymousClass = isClass && (name containsName tpnme.ANON_CLASS_NAME) + final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME) + final def isAnonOrRefinementClass = isAnonymousClass || isRefinementClass + + final def isPackageObject = isModule && name == nme.PACKAGEkw && owner.isPackageClass + final def isPackageObjectClass = isModuleClass && name.toTermName == nme.PACKAGEkw && owner.isPackageClass + final def definedInPackage = owner.isPackageClass || owner.isPackageObjectClass + final def isJavaInterface = isJavaDefined && isTrait + final def needsFlatClasses: Boolean = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass + + // not printed as prefixes + final def isPredefModule = this == PredefModule + final def isScalaPackage = (this == ScalaPackage) || (isPackageObject && owner == ScalaPackageClass) + final def isScalaPackageClass = skipPackageObject == ScalaPackageClass + + /** If this is a package object or package object class, its owner: otherwise this. + */ + final def skipPackageObject: Symbol = if (isPackageObjectClass) owner else this + + /** If this is a constructor, its owner: otherwise this. + */ + final def skipConstructor: Symbol = if (isConstructor) owner else this + + /** Conditions where we omit the prefix when printing a symbol, to avoid + * unpleasantries like Predef.String, $iw.$iw.Foo and <empty>.Bippy. + */ + final def printWithoutPrefix = !settings.debug.value && ( + isScalaPackageClass || isPredefModule || isEffectiveRoot || isAnonOrRefinementClass || isInterpreterWrapper + ) + + /** Is symbol a monomorphic type? + * assumption: if a type starts out as monomorphic, it will not acquire + * type parameters in later phases. + */ + final def isMonomorphicType = + isType && { + var is = infos + (is eq null) || { + while (is.prev ne null) { is = is.prev } + is.info.isComplete && is.info.typeParams.isEmpty + } + } + + def isStrictFP = hasAnnotation(ScalaStrictFPAttr) || (enclClass hasAnnotation ScalaStrictFPAttr) + def isSerializable = info.baseClasses.exists(p => p == SerializableClass || p == JavaSerializableClass) || hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated + def isDeprecated = hasAnnotation(DeprecatedAttr) + def hasBridgeAnnotation = hasAnnotation(BridgeClass) + def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0) + def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1) + // !!! when annotation arguments are not literal strings, but any sort of + // assembly of strings, there is a fair chance they will turn up here not as + // Literal(const) but some arbitrary AST. However nothing in the compiler + // prevents someone from writing a @migration annotation with a calculated + // string. So this needs attention. For now the fact that migration is + // private[scala] ought to provide enough protection. + def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(2) } + def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) } + def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) } + + /** Is this symbol an accessor method for outer? */ + final def isOuterAccessor = { + hasFlag(STABLE | SYNTHETIC) && + originalName == nme.OUTER + } + + /** Is this symbol an accessor method for outer? */ + final def isOuterField = { + hasFlag(SYNTHETIC) && + originalName == nme.OUTER_LOCAL + } + + /** Does this symbol denote a stable value? */ + final def isStable = + isTerm && + !isMutable && + (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE)) && + !(tpe.isVolatile && !hasAnnotation(uncheckedStableClass)) + + def isVirtualClass = + hasFlag(DEFERRED) && isClass + + def isVirtualTrait = + hasFlag(DEFERRED) && isTrait + + def isLiftedMethod = isMethod && hasFlag(LIFTED) + def isCaseClass = isClass && isCase + + /** Does this symbol denote the primary constructor of its enclosing class? */ + final def isPrimaryConstructor = + isConstructor && owner.primaryConstructor == this + + /** Does this symbol denote an auxiliary constructor of its enclosing class? */ + final def isAuxiliaryConstructor = + isConstructor && !isPrimaryConstructor + + /** Is this symbol a synthetic apply or unapply method in a companion object of a case class? */ + final def isCaseApplyOrUnapply = + isMethod && isCase && isSynthetic + + /** Is this symbol a trait which needs an implementation class? */ + final def needsImplClass: Boolean = + isTrait && (!isInterface || hasFlag(lateINTERFACE)) && !isImplClass + + /** Is this a symbol which exists only in the implementation class, not in its trait? */ + final def isImplOnly: Boolean = + hasFlag(PRIVATE) || + (owner.isImplClass || owner.isTrait) && + ((hasFlag(notPRIVATE | LIFTED) && !hasFlag(ACCESSOR | SUPERACCESSOR | MODULE) || isConstructor) || + (hasFlag(LIFTED) && isModule && isMethod)) + + /** Is this symbol a module variable? + * This used to have to test for MUTABLE to distinguish the overloaded + * MODULEVAR/SYNTHETICMETH flag, but now SYNTHETICMETH is gone. + */ + final def isModuleVar = hasFlag(MODULEVAR) + + /** Is this symbol static (i.e. with no outer instance)? */ + final def isStatic: Boolean = + hasFlag(STATIC) || isRoot || owner.isStaticOwner + + /** Is this symbol a static constructor? */ + final def isStaticConstructor: Boolean = + isStaticMember && isClassConstructor + + /** Is this symbol a static member of its class? (i.e. needs to be implemented as a Java static?) */ + final def isStaticMember: Boolean = + hasFlag(STATIC) || owner.isImplClass + + /** Does this symbol denote a class that defines static symbols? */ + final def isStaticOwner: Boolean = + isPackageClass || isModuleClass && isStatic + + /** Is this symbol effectively final? I.e, it cannot be overridden */ + final def isEffectivelyFinal: Boolean = isFinal || isTerm && ( + hasFlag(PRIVATE) || isLocal || owner.isClass && owner.hasFlag(FINAL | MODULE)) + + /** Is this symbol locally defined? I.e. not accessed from outside `this' instance */ + final def isLocal: Boolean = owner.isTerm + + /** Is this symbol a constant? */ + final def isConstant: Boolean = + isStable && (tpe match { + case ConstantType(_) => true + case PolyType(_, ConstantType(_)) => true + case MethodType(_, ConstantType(_)) => true + case NullaryMethodType(ConstantType(_)) => true + case _ => false + }) + + /** Is this class nested in another class or module (not a package)? */ + final def isNestedClass: Boolean = + isClass && !isRoot && !owner.isPackageClass + + /** Is this class locally defined? + * A class is local, if + * - it is anonymous, or + * - its owner is a value + * - it is defined within a local class + */ + final def isLocalClass: Boolean = + isClass && (isAnonOrRefinementClass || isLocal || + !owner.isPackageClass && owner.isLocalClass) + +/* code for fixing nested objects + override final def isModuleClass: Boolean = + super.isModuleClass && !isExpandedModuleClass +*/ + /** Is this class or type defined as a structural refinement type? + */ + final def isStructuralRefinement: Boolean = + (isClass || isType || isModule) && info.normalize/*.underlying*/.isStructuralRefinement + + + /** Is this symbol a member of class `clazz' + */ + def isMemberOf(clazz: Symbol) = + clazz.info.member(name).alternatives contains this + + /** A a member of class `base' is incomplete if + * (1) it is declared deferred or + * (2) it is abstract override and its super symbol in `base' is + * nonexistent or incomplete. + * + * @param base ... + * @return ... + */ + final def isIncompleteIn(base: Symbol): Boolean = + this.isDeferred || + (this hasFlag ABSOVERRIDE) && { + val supersym = superSymbol(base) + supersym == NoSymbol || supersym.isIncompleteIn(base) + } + + // Does not always work if the rawInfo is a SourcefileLoader, see comment + // in "def coreClassesFirst" in Global. + final def exists: Boolean = + this != NoSymbol && (!owner.isPackageClass || { rawInfo.load(this); rawInfo != NoType }) + + final def isInitialized: Boolean = + validTo != NoPeriod + + final def isStableClass: Boolean = { + def hasNoAbstractTypeMember(clazz: Symbol): Boolean = + (clazz hasFlag STABLE) || { + var e = clazz.info.decls.elems + while ((e ne null) && !(e.sym.isAbstractType && info.member(e.sym.name) == e.sym)) + e = e.next + e == null + } + def checkStable() = + (info.baseClasses forall hasNoAbstractTypeMember) && { setFlag(STABLE); true } + isClass && (hasFlag(STABLE) || checkStable()) + } + + + /** The variance of this symbol as an integer */ + final def variance: Int = + if (isCovariant) 1 + else if (isContravariant) -1 + else 0 + +// ------ owner attribute -------------------------------------------------------------- + + def owner: Symbol = rawowner + final def owner_=(owner: Symbol) { + if (originalOwner contains this) () + else originalOwner(this) = rawowner + + rawowner = owner + } + private[Symbols] def flattenName(): Name = { + // TODO: this assertion causes me a lot of trouble in the interpeter in situations + // where everything proceeds smoothly if there's no assert. I don't think calling "name" + // on a symbol is the right place to throw fatal exceptions if things don't look right. + // It really hampers exploration. + assert(rawowner.isClass, "fatal: %s has non-class owner %s after flatten.".format(rawname + idString, rawowner)) + nme.flattenedName(rawowner.name, rawname) + } + + def ownerChain: List[Symbol] = this :: owner.ownerChain + def enclClassChain: List[Symbol] = { + if (this eq NoSymbol) Nil + else if (isClass && !isPackageClass) this :: owner.enclClassChain + else owner.enclClassChain + } + + def ownersIterator: Iterator[Symbol] = new Iterator[Symbol] { + private var current = Symbol.this + def hasNext = current ne NoSymbol + def next = { val r = current; current = current.owner; r } + } + + /** same as ownerChain contains sym, but more efficient, and + * with a twist for refinement classes. A refinement class + * has a transowner X if an of its parents has transowner X. + */ + def hasTransOwner(sym: Symbol): Boolean = { + var o = this + while ((o ne sym) && (o ne NoSymbol)) o = o.owner + (o eq sym) || + isRefinementClass && (info.parents exists (_.typeSymbol.hasTransOwner(sym))) + } + +// ------ name attribute -------------------------------------------------------------- + + def name: Name = rawname + + final def name_=(name: Name) { + if (name != rawname) { + if (owner.isClass) { + var ifs = owner.infos + while (ifs != null) { + ifs.info.decls.rehash(this, name) + ifs = ifs.prev + } + } + rawname = name + } + } + + /** If this symbol has an expanded name, its original name, otherwise its name itself. + * @see expandName + */ + def originalName = nme.originalName(name) + + /** The name of the symbol before decoding, e.g. `\$eq\$eq` instead of `==`. + */ + def encodedName: String = name.toString + + /** The decoded name of the symbol, e.g. `==` instead of `\$eq\$eq`. + */ + def decodedName: String = stripLocalSuffix(NameTransformer.decode(encodedName)) + + /** The encoded full path name of this symbol, where outer names and inner names + * are separated by `separator` characters. + * Never translates expansions of operators back to operator symbol. + * Never adds id. + */ + final def fullName(separator: Char): String = stripLocalSuffix { + if (isRoot || isRootPackage || this == NoSymbol) this.toString + else if (owner.isEffectiveRoot) encodedName + else owner.enclClass.fullName(separator) + separator + encodedName + } + + private def stripLocalSuffix(s: String) = s stripSuffix nme.LOCAL_SUFFIX_STRING + + /** The encoded full path name of this symbol, where outer names and inner names + * are separated by periods. + */ + final def fullName: String = fullName('.') + +// ------ flags attribute -------------------------------------------------------------- + + final def flags: Long = { + val fs = rawflags & phase.flagMask + (fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift) + } + final def flags_=(fs: Long) = rawflags = fs + final def setFlag(mask: Long): this.type = { rawflags = rawflags | mask; this } + final def resetFlag(mask: Long): this.type = { rawflags = rawflags & ~mask; this } + final def getFlag(mask: Long): Long = flags & mask + final def resetFlags { rawflags = rawflags & TopLevelCreationFlags } + + /** Does symbol have ANY flag in `mask` set? */ + final def hasFlag(mask: Long): Boolean = (flags & mask) != 0L + + /** Does symbol have ALL the flags in `mask` set? */ + final def hasAllFlags(mask: Long): Boolean = (flags & mask) == mask + + /** The class or term up to which this symbol is accessible, + * or RootClass if it is public. + */ + def accessBoundary(base: Symbol): Symbol = { + if (hasFlag(PRIVATE) || isLocal) owner + else if (hasAccessBoundary && !phase.erasedTypes) privateWithin + else if (hasFlag(PROTECTED)) base + else RootClass + } + + def isLessAccessibleThan(other: Symbol): Boolean = { + val tb = this.accessBoundary(owner) + val ob1 = other.accessBoundary(owner) + val ob2 = ob1.linkedClassOfClass + var o = tb + while (o != NoSymbol && o != ob1 && o != ob2) { + o = o.owner + } + o != NoSymbol && o != tb + } + + /** See comment in HasFlags for how privateWithin combines with flags. + */ + private[this] var _privateWithin: Symbol = _ + def privateWithin = _privateWithin + def privateWithin_=(sym: Symbol) { _privateWithin = sym } + + /** Does symbol have a private or protected qualifier set? */ + final def hasAccessBoundary = (privateWithin != null) && (privateWithin != NoSymbol) + +// ------ info and type ------------------------------------------------------------------- + + private[Symbols] var infos: TypeHistory = null + + /** Get type. The type of a symbol is: + * for a type symbol, the type corresponding to the symbol itself, + * @M you should use tpeHK for a type symbol with type parameters if + * the kind of the type need not be *, as tpe introduces dummy arguments + * to generate a type of kind * + * for a term symbol, its usual type + */ + def tpe: Type = info + + /** Get type info associated with symbol at current phase, after + * ensuring that symbol is initialized (i.e. type is completed). + */ + def info: Type = try { + var cnt = 0 + while (validTo == NoPeriod) { + //if (settings.debug.value) System.out.println("completing " + this);//DEBUG + assert(infos ne null, this.name) + assert(infos.prev eq null, this.name) + val tp = infos.info + //if (settings.debug.value) System.out.println("completing " + this.rawname + tp.getClass());//debug + + if ((rawflags & LOCKED) != 0L) { // rolled out once for performance + lock { + setInfo(ErrorType) + throw CyclicReference(this, tp) + } + } else { + rawflags |= LOCKED +// activeLocks += 1 + // lockedSyms += this + } + val current = phase + try { + phase = phaseOf(infos.validFrom) + tp.complete(this) + } finally { + unlock() + phase = current + } + cnt += 1 + // allow for two completions: + // one: sourceCompleter to LazyType, two: LazyType to completed type + if (cnt == 3) abort("no progress in completing " + this + ":" + tp) + } + val result = rawInfo + result + } catch { + case ex: CyclicReference => + if (settings.debug.value) println("... trying to complete "+this) + throw ex + } + + def info_=(info: Type) { + assert(info ne null) + infos = TypeHistory(currentPeriod, info, null) + unlock() + validTo = if (info.isComplete) currentPeriod else NoPeriod + } + + /** Set initial info. */ + def setInfo(info: Type): this.type = { info_=(info); this } + + def setInfoOwnerAdjusted(info: Type): this.type = setInfo(info.atOwner(this)) + + /** Set new info valid from start of this phase. */ + final def updateInfo(info: Type): Symbol = { + assert(phaseId(infos.validFrom) <= phase.id) + if (phaseId(infos.validFrom) == phase.id) infos = infos.prev + infos = TypeHistory(currentPeriod, info, infos) + validTo = if (info.isComplete) currentPeriod else NoPeriod + this + } + + def hasRawInfo: Boolean = infos ne null + + /** Return info without checking for initialization or completing */ + def rawInfo: Type = { + var infos = this.infos + assert(infos != null) + val curPeriod = currentPeriod + val curPid = phaseId(curPeriod) + + if (validTo != NoPeriod) { + // skip any infos that concern later phases + while (curPid < phaseId(infos.validFrom) && infos.prev != null) + infos = infos.prev + + if (validTo < curPeriod) { + // adapt any infos that come from previous runs + val current = phase + try { + infos = adaptInfos(infos) + + //assert(runId(validTo) == currentRunId, name) + //assert(runId(infos.validFrom) == currentRunId, name) + + if (validTo < curPeriod) { + var itr = infoTransformers.nextFrom(phaseId(validTo)) + infoTransformers = itr; // caching optimization + while (itr.pid != NoPhase.id && itr.pid < current.id) { + phase = phaseWithId(itr.pid) + val info1 = itr.transform(this, infos.info) + if (info1 ne infos.info) { + infos = TypeHistory(currentPeriod + 1, info1, infos) + this.infos = infos + } + validTo = currentPeriod + 1 // to enable reads from same symbol during info-transform + itr = itr.next + } + validTo = if (itr.pid == NoPhase.id) curPeriod + else period(currentRunId, itr.pid) + } + } finally { + phase = current + } + } + } + infos.info + } + + // adapt to new run in fsc. + private def adaptInfos(infos: TypeHistory): TypeHistory = + if (infos == null || runId(infos.validFrom) == currentRunId) { + infos + } else { + val prev1 = adaptInfos(infos.prev) + if (prev1 ne infos.prev) prev1 + else { + def adaptToNewRun(info: Type): Type = + if (isPackageClass) info else adaptToNewRunMap(info) + val pid = phaseId(infos.validFrom) + validTo = period(currentRunId, pid) + phase = phaseWithId(pid) + val info1 = adaptToNewRun(infos.info) + if (info1 eq infos.info) { + infos.validFrom = validTo + infos + } else { + this.infos = TypeHistory(validTo, info1, prev1) + this.infos + } + } + } + + /** Initialize the symbol */ + final def initialize: this.type = { + if (!isInitialized) info + this + } + + /** Was symbol's type updated during given phase? */ + final def isUpdatedAt(pid: Phase#Id): Boolean = { + var infos = this.infos + while ((infos ne null) && phaseId(infos.validFrom) != pid + 1) infos = infos.prev + infos ne null + } + + /** Was symbol's type updated during given phase? */ + final def hasTypeAt(pid: Phase#Id): Boolean = { + var infos = this.infos + while ((infos ne null) && phaseId(infos.validFrom) > pid) infos = infos.prev + infos ne null + } + + /** Modify term symbol's type so that a raw type C is converted to an existential C[_] + * + * This is done in checkAccessible and overriding checks in refchecks + * We can't do this on class loading because it would result in infinite cycles. + */ + final def cookJavaRawInfo() { + if (hasFlag(TRIEDCOOKING)) return else setFlag(TRIEDCOOKING) // only try once... + val oldInfo = info + doCookJavaRawInfo() + } + + protected def doCookJavaRawInfo(): Unit + + + /** The type constructor of a symbol is: + * For a type symbol, the type corresponding to the symbol itself, + * excluding parameters. + * Not applicable for term symbols. + */ + def typeConstructor: Type = + abort("typeConstructor inapplicable for " + this) + + /** @M -- tpe vs tpeHK: + * Symbol::tpe creates a TypeRef that has dummy type arguments to get a type of kind * + * Symbol::tpeHK creates a TypeRef without type arguments, but with type params --> higher-kinded if non-empty list of tpars + * calling tpe may hide errors or introduce spurious ones + * (e.g., when deriving a type from the symbol of a type argument that must be higher-kinded) + * as far as I can tell, it only makes sense to call tpe in conjunction with a substitution that replaces the generated dummy type arguments by their actual types + */ + def tpeHK = if (isType) typeConstructor else tpe // @M! used in memberType + + /** The type parameters of this symbol, without ensuring type completion. + * assumption: if a type starts out as monomorphic, it will not acquire + * type parameters later. + */ + def unsafeTypeParams: List[Symbol] = + if (isMonomorphicType) List() + else { + val current = phase + try { + while ((phase.prev ne NoPhase) && phase.prev.keepsTypeParams) phase = phase.prev + if (phase ne current) phase = phase.next + if (settings.debug.value && settings.verbose.value && (phase ne current)) + log("checking unsafeTypeParams(" + this + ") at: " + current + " reading at: " + phase) + rawInfo.typeParams + } finally { + phase = current + } + } + + /** The type parameters of this symbol. + * assumption: if a type starts out as monomorphic, it will not acquire + * type parameters later. + */ + def typeParams: List[Symbol] = + if (isMonomorphicType) + List() + else { + if (validTo == NoPeriod) { + val current = phase + try { + phase = phaseOf(infos.validFrom) + rawInfo.load(this) + } finally { + phase = current + } + } + rawInfo.typeParams + } + + /** The value parameter sections of this symbol. + */ + def paramss: List[List[Symbol]] = info.paramss + def hasParamWhich(cond: Symbol => Boolean) = paramss exists (_ exists cond) + + /** The least proper supertype of a class; includes all parent types + * and refinement where needed. You need to compute that in a situation like this: + * { + * class C extends P { ... } + * new C + * } + */ + def classBound: Type = { + val tp = refinedType(info.parents, owner) + val thistp = tp.typeSymbol.thisType + val oldsymbuf = new ListBuffer[Symbol] + val newsymbuf = new ListBuffer[Symbol] + for (sym <- info.decls.toList) { + // todo: what about public references to private symbols? + if (sym.isPublic && !sym.isConstructor) { + oldsymbuf += sym + newsymbuf += ( + if (sym.isClass) + tp.typeSymbol.newAbstractType(sym.pos, sym.name.toTypeName).setInfo(sym.existentialBound) + else + sym.cloneSymbol(tp.typeSymbol)) + } + } + val oldsyms = oldsymbuf.toList + val newsyms = newsymbuf.toList + for (sym <- newsyms) { + addMember(thistp, tp, sym.setInfo(sym.info.substThis(this, thistp).substSym(oldsyms, newsyms))) + } + tp + } + + /** If we quantify existentially over this symbol, + * the bound of the type variable that stands for it + * pre: symbol is a term, a class, or an abstract type (no alias type allowed) + */ + def existentialBound: Type = + if (this.isClass) + polyType(this.typeParams, TypeBounds.upper(this.classBound)) + else if (this.isAbstractType) + this.info + else if (this.isTerm) + TypeBounds.upper(intersectionType(List(this.tpe, SingletonClass.tpe))) + else + abort("unexpected alias type: "+this) + + /** Reset symbol to initial state + */ + def reset(completer: Type) { + resetFlags + infos = null + validTo = NoPeriod + //limit = NoPhase.id + setInfo(completer) + } + + /** + * Adds the interface scala.Serializable to the parents of a ClassInfoType. + * Note that the tree also has to be updated accordingly. + */ + def makeSerializable() { + info match { + case ci @ ClassInfoType(_, _, _) => + updateInfo(ci.copy(parents = ci.parents ::: List(SerializableClass.tpe))) + case i => + abort("Only ClassInfoTypes can be made serializable: "+ i) + } + } + +// ----- setters implemented in selected subclasses ------------------------------------- + + def typeOfThis_=(tp: Type) { throw new UnsupportedOperationException("typeOfThis_= inapplicable for " + this) } + def sourceModule_=(sym: Symbol) { throw new UnsupportedOperationException("sourceModule_= inapplicable for " + this) } + def addChild(sym: Symbol) { throw new UnsupportedOperationException("addChild inapplicable for " + this) } + +// ----- annotations ------------------------------------------------------------ + + private var rawannots: List[AnnotationInfoBase] = Nil + def rawAnnotations = rawannots + + /* Used in namer to check whether annotations were already assigned or not */ + def hasAssignedAnnotations = rawannots.nonEmpty + + /** After the typer phase (before, look at the definition's Modifiers), contains + * the annotations attached to member a definition (class, method, type, field). + */ + def annotations: List[AnnotationInfo] = { + // .initialize: the type completer of the symbol parses the annotations, + // see "def typeSig" in Namers + val annots1 = initialize.rawannots map { + case x: LazyAnnotationInfo => x.annot() + case x: AnnotationInfo => x + } filterNot (_.atp.isError) + rawannots = annots1 + annots1 + } + + def setAnnotations(annots: List[AnnotationInfoBase]): this.type = { + this.rawannots = annots + this + } + + def addAnnotation(annot: AnnotationInfo) { + setAnnotations(annot :: this.rawannots) + } + + /** Does this symbol have an annotation of the given class? */ + def hasAnnotation(cls: Symbol) = + getAnnotation(cls).isDefined + + def getAnnotation(cls: Symbol): Option[AnnotationInfo] = + annotations find (_.atp.typeSymbol == cls) + + /** Remove all annotations matching the given class. */ + def removeAnnotation(cls: Symbol): Unit = + setAnnotations(annotations filterNot (_.atp.typeSymbol == cls)) + +// ------ comparisons ---------------------------------------------------------------- + + /** A total ordering between symbols that refines the class + * inheritance graph (i.e. subclass.isLess(superclass) always holds). + * the ordering is given by: (_.isType, -_.baseTypeSeq.length) for type symbols, followed by `id'. + */ + final def isLess(that: Symbol): Boolean = { + def baseTypeSeqLength(sym: Symbol) = + if (sym.isAbstractType) 1 + sym.info.bounds.hi.baseTypeSeq.length + else sym.info.baseTypeSeq.length + if (this.isType) + (that.isType && + { val diff = baseTypeSeqLength(this) - baseTypeSeqLength(that) + diff > 0 || diff == 0 && this.id < that.id }) + else + that.isType || this.id < that.id + } + + /** A partial ordering between symbols. + * (this isNestedIn that) holds iff this symbol is defined within + * a class or method defining that symbol + */ + final def isNestedIn(that: Symbol): Boolean = + owner == that || owner != NoSymbol && (owner isNestedIn that) + + /** Is this class symbol a subclass of that symbol? */ + final def isNonBottomSubClass(that: Symbol): Boolean = + this == that || this.isError || that.isError || + info.baseTypeIndex(that) >= 0 + + final def isSubClass(that: Symbol): Boolean = { + isNonBottomSubClass(that) || + this == NothingClass || + this == NullClass && + (that == AnyClass || + that != NothingClass && (that isSubClass AnyRefClass)) + } + final def isNumericSubClass(that: Symbol): Boolean = + definitions.isNumericSubClass(this, that) + +// ------ overloaded alternatives ------------------------------------------------------ + + def alternatives: List[Symbol] = + if (hasFlag(OVERLOADED)) info.asInstanceOf[OverloadedType].alternatives + else List(this) + + def filter(cond: Symbol => Boolean): Symbol = + if (hasFlag(OVERLOADED)) { + //assert(info.isInstanceOf[OverloadedType], "" + this + ":" + info);//DEBUG + val alts = alternatives + val alts1 = alts filter cond + if (alts1 eq alts) this + else if (alts1.isEmpty) NoSymbol + else if (alts1.tail.isEmpty) alts1.head + else owner.newOverloaded(info.prefix, alts1) + } else if (this == NoSymbol || cond(this)) { + this + } else NoSymbol + + def suchThat(cond: Symbol => Boolean): Symbol = { + val result = filter(cond) + assert(!(result hasFlag OVERLOADED), result.alternatives) + result + } + +// ------ cloneing ------------------------------------------------------------------- + + /** A clone of this symbol */ + final def cloneSymbol: Symbol = + cloneSymbol(owner) + + /** A clone of this symbol, but with given owner */ + final def cloneSymbol(owner: Symbol): Symbol = { + val newSym = cloneSymbolImpl(owner) + newSym.privateWithin = privateWithin + newSym.setInfo(info.cloneInfo(newSym)) + .setFlag(this.rawflags).setAnnotations(this.annotations) + } + + /** Internal method to clone a symbol's implementation without flags or type + */ + def cloneSymbolImpl(owner: Symbol): Symbol + +// ------ access to related symbols -------------------------------------------------- + + /** The next enclosing class */ + def enclClass: Symbol = if (isClass) this else owner.enclClass + + /** The next enclosing method */ + def enclMethod: Symbol = if (isSourceMethod) this else owner.enclMethod + + /** The primary constructor of a class */ + def primaryConstructor: Symbol = { + var c = info.decl( + if (isTrait || isImplClass) nme.MIXIN_CONSTRUCTOR + else nme.CONSTRUCTOR) + c = if (c hasFlag OVERLOADED) c.alternatives.head else c + //assert(c != NoSymbol) + c + } + + /** The self symbol of a class with explicit self type, or else the + * symbol itself. + */ + def thisSym: Symbol = this + + /** The type of `this' in a class, or else the type of the symbol itself. */ + def typeOfThis = thisSym.tpe + + /** If symbol is a class, the type <code>this.type</code> in this class, + * otherwise <code>NoPrefix</code>. + * We always have: thisType <:< typeOfThis + */ + def thisType: Type = NoPrefix + + /** Return every accessor of a primary constructor parameter in this case class. + * The scope declarations may be out of order because fields with less than private + * access are first given a regular getter, then a new renamed getter which comes + * later in the declaration list. For this reason we have to pinpoint the + * right accessors by starting with the original fields (which will be in the right + * order) and looking for getters with applicable names. The getters may have the + * standard name "foo" or may have been renamed to "foo$\d+" in SyntheticMethods. + * See ticket #1373. + */ + final def caseFieldAccessors: List[Symbol] = { + val allWithFlag = info.decls.toList filter (_.isCaseAccessor) + val (accessors, fields) = allWithFlag partition (_.isMethod) + + def findAccessor(field: Symbol): Symbol = { + // There is another renaming the field may have undergone, for instance as in + // ticket #2175: case class Property[T](private var t: T), t becomes Property$$t. + // So we use the original name everywhere. + val getterName = nme.getterName(field.originalName) + + // Note this is done in two passes intentionally, to ensure we pick up the original + // getter if present before looking for the renamed getter. + def origGetter = accessors find (_.originalName == getterName) + def renamedGetter = accessors find (_.originalName startsWith (getterName + "$")) + val accessorName = origGetter orElse renamedGetter + + // This fails more gracefully rather than throw an Error as it used to because + // as seen in #2625, we can reach this point with an already erroneous tree. + accessorName getOrElse NoSymbol + // throw new Error("Could not find case accessor for %s in %s".format(field, this)) + } + + fields map findAccessor + } + + final def constrParamAccessors: List[Symbol] = + info.decls.toList filter (sym => !sym.isMethod && sym.isParamAccessor) + + /** The symbol accessed by this accessor (getter or setter) function. */ + final def accessed: Symbol = accessed(owner.info) + + /** The symbol accessed by this accessor function, but with given owner type */ + final def accessed(ownerTp: Type): Symbol = { + assert(hasAccessorFlag) + ownerTp.decl(nme.getterToLocal(if (isSetter) nme.setterToGetter(name) else name)) + } + + /** The module corresponding to this module class (note that this + * is not updated when a module is cloned), or NoSymbol if this is not a ModuleClass + */ + def sourceModule: Symbol = NoSymbol + + /** The implementation class of a trait */ + final def implClass: Symbol = owner.info.decl(nme.implClassName(name)) + + /** The class that is logically an outer class of given `clazz'. + * This is the enclosing class, except for classes defined locally to constructors, + * where it is the outer class of the enclosing class + */ + final def outerClass: Symbol = + if (owner.isClass) owner + else if (isClassLocalToConstructor) owner.enclClass.outerClass + else owner.outerClass + + /** For a paramaccessor: a superclass paramaccessor for which this symbol + * is an alias, NoSymbol for all others + */ + def alias: Symbol = NoSymbol + + /** For a lazy value, its lazy accessor. NoSymbol for all others */ + def lazyAccessor: Symbol = NoSymbol + + /** If this is a lazy value, the lazy accessor; otherwise this symbol. */ + def lazyAccessorOrSelf: Symbol = if (isLazy) lazyAccessor else this + + /** For an outer accessor: The class from which the outer originates. + * For all other symbols: NoSymbol + */ + def outerSource: Symbol = NoSymbol + + /** The superclass of this class */ + def superClass: Symbol = if (info.parents.isEmpty) NoSymbol else info.parents.head.typeSymbol + + /** The directly or indirectly inherited mixins of this class + * except for mixin classes inherited by the superclass. Mixin classes appear + * in linearization order. + */ + def mixinClasses: List[Symbol] = { + val sc = superClass + ancestors takeWhile (sc ne) + } + + /** All directly or indirectly inherited classes. + */ + def ancestors: List[Symbol] = info.baseClasses drop 1 + + /** The package class containing this symbol, or NoSymbol if there + * is not one. */ + def enclosingPackageClass: Symbol = + if (this == NoSymbol) this else { + var packSym = this.owner + while (packSym != NoSymbol && !packSym.isPackageClass) + packSym = packSym.owner + packSym + } + + /** The package containing this symbol, or NoSymbol if there + * is not one. */ + def enclosingPackage: Symbol = { + val packSym = enclosingPackageClass + if (packSym != NoSymbol) packSym.companionModule + else packSym + } + + /** Return the original enclosing method of this symbol. It should return + * the same thing as enclMethod when called before lambda lift, + * but it preserves the original nesting when called afterwards. + */ + def originalEnclosingMethod: Symbol = { + if (isMethod) this + else { + val owner = originalOwner.getOrElse(this, rawowner) + if (isLocalDummy) owner.enclClass.primaryConstructor + else owner.originalEnclosingMethod + } + } + + /** The method or class which logically encloses the current symbol. + * If the symbol is defined in the initialization part of a template + * this is the template's primary constructor, otherwise it is + * the physically enclosing method or class. + * + * Example 1: + * + * def f() { val x = { def g() = ...; g() } } + * + * In this case the owner chain of `g' is `x', followed by `f' and + * `g.logicallyEnclosingMember == f`. + * + * Example 2: + * + * class C { + * def <init> = { ... } + * val x = { def g() = ...; g() } } + * } + * + * In this case the owner chain of `g' is `x', followed by `C' but + * g.logicallyEnclosingMember is the primary constructor symbol `<init>' + * (or, for traits: `$init') of `C'. + * + */ + def logicallyEnclosingMember: Symbol = + if (isLocalDummy) enclClass.primaryConstructor + else if (isMethod || isClass) this + else owner.logicallyEnclosingMember + + /** The top-level class containing this symbol */ + def toplevelClass: Symbol = + if (owner.isPackageClass) { + if (isClass) this else moduleClass + } else owner.toplevelClass + + /** Is this symbol defined in the same scope and compilation unit as `that' symbol? + */ + def isCoDefinedWith(that: Symbol) = ( + (this.rawInfo ne NoType) && + (this.owner == that.owner) && { + !this.owner.isPackageClass || + (this.sourceFile eq null) || + (that.sourceFile eq null) || + (this.sourceFile == that.sourceFile) || { + // recognize companion object in separate file and fail, else compilation + // appears to succeed but highly opaque errors come later: see bug #1286 + if (this.sourceFile.path != that.sourceFile.path) + throw InvalidCompanions(this, that) + + false + } + } + ) + + /** The internal representation of classes and objects: + * + * class Foo is "the class" or sometimes "the plain class" + * object Foo is "the module" + * class Foo$ is "the module class" (invisible to the user: it implements object Foo) + * + * class Foo < + * ^ ^ (2) \ + * | | | \ + * | (5) | (3) + * | | | \ + * (1) v v \ + * object Foo (4)-> > class Foo$ + * + * (1) companionClass + * (2) companionModule + * (3) linkedClassOfClass + * (4) moduleClass + * (5) companionSymbol + */ + + /** For a module or case factory: the class with the same name in the same package. + * For all others: NoSymbol + * Note: does not work for classes owned by methods, see Namers.companionClassOf + * + * object Foo . companionClass --> class Foo + */ + final def companionClass: Symbol = { + if (this != NoSymbol) + flatOwnerInfo.decl(name.toTypeName).suchThat(_ isCoDefinedWith this) + else NoSymbol + } + + /** A helper method that factors the common code used the discover a + * companion module of a class. If a companion module exists, its symbol is + * returned, otherwise, `NoSymbol` is returned. The method assumes that + * `this` symbol has already been checked to be a class (using `isClass`). + */ + private final def companionModule0: Symbol = + flatOwnerInfo.decl(name.toTermName).suchThat( + sym => sym.hasFlag(MODULE) && (sym isCoDefinedWith this) && !sym.isMethod) + + /** For a class: the module or case class factory with the same name in the same package. + * For all others: NoSymbol + * Note: does not work for modules owned by methods, see Namers.companionModuleOf + * + * class Foo . companionModule --> object Foo + */ + final def companionModule: Symbol = + if (isClass && !isRefinementClass) companionModule0 + else NoSymbol + + /** For a module: its linked class + * For a plain class: its linked module or case factory. + * Note: does not work for modules owned by methods, see Namers.companionSymbolOf + * + * class Foo <-- companionSymbol --> object Foo + */ + final def companionSymbol: Symbol = + if (isTerm) companionClass + else if (isClass) companionModule0 + else NoSymbol + + /** For a module class: its linked class + * For a plain class: the module class of its linked module. + * + * class Foo <-- linkedClassOfClass --> class Foo$ + */ + final def linkedClassOfClass: Symbol = + if (isModuleClass) companionClass else companionModule.moduleClass + + /** + * Returns the rawInfo of the owner. If the current phase has flat classes, + * it first applies all pending type maps to this symbol. + * + * assume this is the ModuleSymbol for B in the following definition: + * package p { class A { object B { val x = 1 } } } + * + * The owner after flatten is "package p" (see "def owner"). The flatten type map enters + * symbol B in the decls of p. So to find a linked symbol ("object B" or "class B") + * we need to apply flatten to B first. Fixes #2470. + */ + private final def flatOwnerInfo: Type = { + if (needsFlatClasses) + info + owner.rawInfo + } + + /** If this symbol is an implementation class, its interface, otherwise the symbol itself + * The method follows two strategies to determine the interface. + * - during or after erasure, it takes the last parent of the implementation class + * (which is always the interface, by convention) + * - before erasure, it looks up the interface name in the scope of the owner of the class. + * This only works for implementation classes owned by other classes or traits. + */ + final def toInterface: Symbol = + if (isImplClass) { + val result = + if (phase.next.erasedTypes) { + assert(!tpe.parents.isEmpty, this) + tpe.parents.last.typeSymbol + } else { + owner.info.decl(nme.interfaceName(name)) + } + assert(result != NoSymbol, this) + result + } else this + + /** The module class corresponding to this module. + */ + def moduleClass: Symbol = NoSymbol + + /** The non-private symbol whose type matches the type of this symbol + * in in given class. + * + * @param ofclazz The class containing the symbol's definition + * @param site The base type from which member types are computed + */ + final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol = + ofclazz.info.nonPrivateDecl(name).filter(sym => + !sym.isTerm || (site.memberType(this) matches site.memberType(sym))) + + /** The non-private member of `site' whose type and name match the type of this symbol + */ + final def matchingSymbol(site: Type, admit: Long = 0L): Symbol = + site.nonPrivateMemberAdmitting(name, admit).filter(sym => + !sym.isTerm || (site.memberType(this) matches site.memberType(sym))) + + /** The symbol overridden by this symbol in given class `ofclazz'. + * @pre 'ofclazz' is a base class of this symbol's owner. + */ + final def overriddenSymbol(ofclazz: Symbol): Symbol = + if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, owner.thisType) + + /** The symbol overriding this symbol in given subclass `ofclazz' + * @pre: `ofclazz' is a subclass of this symbol's owner + */ + final def overridingSymbol(ofclazz: Symbol): Symbol = + if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, ofclazz.thisType) + + /** Returns all symbols overriden by this symbol + */ + final def allOverriddenSymbols: List[Symbol] = + if (!owner.isClass) Nil + else owner.ancestors map overriddenSymbol filter (_ != NoSymbol) + + /** Returns all symbols overridden by this symbol, plus all matching symbols + * defined in parents of the selftype + */ + final def extendedOverriddenSymbols: List[Symbol] = + if (!owner.isClass) Nil + else owner.thisSym.ancestors map overriddenSymbol filter (_ != NoSymbol) + + /** The symbol accessed by a super in the definition of this symbol when + * seen from class `base'. This symbol is always concrete. + * pre: `this.owner' is in the base class sequence of `base'. + */ + final def superSymbol(base: Symbol): Symbol = { + var bcs = base.info.baseClasses.dropWhile(owner !=).tail + var sym: Symbol = NoSymbol + while (!bcs.isEmpty && sym == NoSymbol) { + if (!bcs.head.isImplClass) + sym = matchingSymbol(bcs.head, base.thisType).suchThat(!_.isDeferred) + bcs = bcs.tail + } + sym + } + + /** The getter of this value or setter definition in class `base', or NoSymbol if + * none exists. + */ + final def getter(base: Symbol): Symbol = { + val getterName = if (isSetter) nme.setterToGetter(name) else nme.getterName(name) + base.info.decl(getterName) filter (_.hasAccessorFlag) + } + + /** The setter of this value or getter definition, or NoSymbol if none exists */ + final def setter(base: Symbol): Symbol = setter(base, false) + + final def setter(base: Symbol, hasExpandedName: Boolean): Symbol = { + var sname = nme.getterToSetter(nme.getterName(name)) + if (hasExpandedName) sname = nme.expandedSetterName(sname, base) + base.info.decl(sname) filter (_.hasAccessorFlag) + } + + /** The case module corresponding to this case class + * @pre case class is a member of some other class or package + */ + final def caseModule: Symbol = { + var modname = name.toTermName + if (privateWithin.isClass && !privateWithin.isModuleClass && !hasFlag(EXPANDEDNAME)) + modname = nme.expandedName(modname, privateWithin) + initialize.owner.info.decl(modname).suchThat(_.isModule) + } + + /** If this symbol is a type parameter skolem (not an existential skolem!) + * its corresponding type parameter, otherwise this */ + def deSkolemize: Symbol = this + + /** If this symbol is an existential skolem the location (a Tree or null) + * where it was unpacked. Resulttype is AnyRef because trees are not visible here. */ + def unpackLocation: AnyRef = null + + /** Remove private modifier from symbol `sym's definition. If `sym' is a + * term symbol rename it by expanding its name to avoid name clashes + */ + final def makeNotPrivate(base: Symbol) { + if (this hasFlag PRIVATE) { + setFlag(notPRIVATE) + if (isMethod && !isDeferred) setFlag(lateFINAL) + if (!isStaticModule && !isClassConstructor) { + expandName(base) + if (isModule) moduleClass.makeNotPrivate(base) + } + } + } + + /** change name by appending $$<fully-qualified-name-of-class `base'> + * Do the same for any accessed symbols or setters/getters + */ + def expandName(base: Symbol) { + if (this.isTerm && this != NoSymbol && !hasFlag(EXPANDEDNAME)) { + setFlag(EXPANDEDNAME) + if (hasAccessorFlag && !isDeferred) { + accessed.expandName(base) + } else if (hasGetter) { + getter(owner).expandName(base) + setter(owner).expandName(base) + } + name = nme.expandedName(name, base) + if (isType) name = name + } + } +/* code for fixing nested objects + def expandModuleClassName() { + name = newTypeName(name.toString + "$") + } + + def isExpandedModuleClass: Boolean = name(name.length - 1) == '$' +*/ + def sourceFile: AbstractFile = + if (isModule) moduleClass.sourceFile + else toplevelClass.sourceFile + + def sourceFile_=(f: AbstractFile) { + abort("sourceFile_= inapplicable for " + this) + } + + /** If this is a sealed class, its known direct subclasses. + * Otherwise, the empty set. + */ + def children: Set[Symbol] = Set() + + /** Recursively assemble all children of this symbol. + */ + def sealedDescendants: Set[Symbol] = children.flatMap(_.sealedDescendants) + this + + def orElse[T](alt: => Symbol): Symbol = if (this ne NoSymbol) this else alt + +// ------ toString ------------------------------------------------------------------- + + /** A tag which (in the ideal case) uniquely identifies class symbols */ + final def tag = fullName.## + + /** The simple name of this Symbol */ + final def simpleName: Name = name + + /** The String used to order otherwise identical sealed symbols. + * This uses data which is stable across runs and variable classpaths + * (the initial Name) before falling back on id, which varies depending + * on exactly when a symbol is loaded. + */ + final def sealedSortName = initName + "#" + id + + /** String representation of symbol's definition key word */ + final def keyString: String = + if (isJavaInterface) "interface" + else if (isTrait) "trait" + else if (isClass) "class" + else if (isType && !isParameter) "type" + else if (isVariable) "var" + else if (isPackage) "package" + else if (isModule) "object" + else if (isSourceMethod) "def" + else if (isTerm && (!isParameter || isParamAccessor)) "val" + else "" + + /** Accurate string representation of symbols' kind, suitable for developers. */ + final def accurateKindString: String = + if (isPackage) "package" + else if (isPackageClass) "package class" + else if (isPackageObject) "package object" + else if (isPackageObjectClass) "package object class" + else if (isRefinementClass) "refinement class" + else if (isModule) "module" + else if (isModuleClass) "module class" + else sanitizedKindString + + /** String representation of symbol's kind, suitable for the masses. */ + private def sanitizedKindString: String = + if (isPackage || isPackageClass) "package" + else if (isModule || isModuleClass) "object" + else if (isAnonymousClass) "anonymous class" + else if (isRefinementClass) "" + else if (isTrait) "trait" + else if (isClass) "class" + else if (isType) "type" + else if (isTerm && isLazy) "lazy value" + else if (isVariable) "variable" + else if (isClassConstructor) "constructor" + else if (isSourceMethod) "method" + else if (isTerm) "value" + else "" + + final def kindString: String = + if (settings.debug.value) accurateKindString + else sanitizedKindString + + /** If the name of the symbol's owner should be used when you care about + * seeing an interesting name: in such cases this symbol is e.g. a method + * parameter with a synthetic name, a constructor named "this", an object + * "package", etc. The kind string, if non-empty, will be phrased relative + * to the name of the owner. + */ + def hasMeaninglessName = ( + isSetterParameter // x$1 + || isClassConstructor // this + || isPackageObject // package + || isPackageObjectClass // package$ + || isRefinementClass // <refinement> + ) + + /** String representation of symbol's simple name. + * If !settings.debug translates expansions of operators back to operator symbol. + * E.g. $eq => =. + * If settings.uniqid, adds id. + */ + def nameString = decodedName + idString + + /** If settings.uniqid is set, the symbol's id, else "" */ + final def idString = if (settings.uniqid.value) "#"+id else "" + + /** String representation, including symbol's kind e.g., "class Foo", "method Bar". + * If hasMeaninglessName is true, uses the owner's name to disambiguate identity. + */ + override def toString = compose( + kindString, + if (hasMeaninglessName) owner.nameString else nameString + ) + + /** String representation of location. + */ + def ownsString = { + val owns = owner.skipPackageObject + if (owns.isClass && !owns.printWithoutPrefix && !isScalaPackageClass) "" + owns + else "" + } + + /** String representation of location, plus a preposition. Doesn't do much, + * for backward compatibility reasons. + */ + def locationString = ownsString match { + case "" => "" + case s => " in " + s + } + def fullLocationString = toString + locationString + + /** String representation of symbol's definition following its name */ + final def infoString(tp: Type): String = { + def typeParamsString: String = tp match { + case PolyType(tparams, _) if tparams.nonEmpty => + (tparams map (_.defString)).mkString("[", ",", "]") + case _ => + "" + } + if (isClass) + typeParamsString + " extends " + tp.resultType + else if (isAliasType) + typeParamsString + " = " + tp.resultType + else if (isAbstractType) + typeParamsString + { + tp.resultType match { + case TypeBounds(lo, hi) => + (if (lo.typeSymbol == NothingClass) "" else " >: " + lo) + + (if (hi.typeSymbol == AnyClass) "" else " <: " + hi) + case rtp => + "<: " + rtp + } + } + else if (isModule) + moduleClass.infoString(tp) + else + tp match { + case PolyType(tparams, res) => + typeParamsString + infoString(res) + case NullaryMethodType(res) => + infoString(res) + case MethodType(params, res) => + params.map(_.defString).mkString("(", ",", ")") + infoString(res) + case _ => + ": " + tp + } + } + + def infosString = infos.toString() + + def hasFlagsToString(mask: Long): String = flagsToString( + flags & mask, + if (hasAccessBoundary) privateWithin.toString else "" + ) + + /** String representation of symbol's variance */ + def varianceString: String = + if (variance == 1) "+" + else if (variance == -1) "-" + else "" + + def defaultFlagMask = + if (settings.debug.value) -1L + else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE + else ExplicitFlags + + def defaultFlagString = hasFlagsToString(defaultFlagMask) + + /** String representation of symbol's definition */ + def defString = compose( + defaultFlagString, + keyString, + varianceString + nameString + ( + if (hasRawInfo) infoString(rawInfo) else "<_>" + ) + ) + + /** Concatenate strings separated by spaces */ + private def compose(ss: String*) = ss filter (_ != "") mkString " " + + def isSingletonExistential = + nme.isSingletonName(name) && (info.bounds.hi.typeSymbol isSubClass SingletonClass) + + /** String representation of existentially bound variable */ + def existentialToString = + if (isSingletonExistential && !settings.debug.value) + "val " + nme.dropSingletonName(name) + ": " + dropSingletonType(info.bounds.hi) + else defString + } + + /** A class for term symbols */ + class TermSymbol(initOwner: Symbol, initPos: Position, initName: TermName) + extends Symbol(initOwner, initPos, initName) { + final override def isTerm = true + + override def name: TermName = super.name + privateWithin = NoSymbol + + var referenced: Symbol = NoSymbol + + def cloneSymbolImpl(owner: Symbol): Symbol = + new TermSymbol(owner, pos, name).copyAttrsFrom(this) + + def copyAttrsFrom(original: TermSymbol): this.type = { + referenced = original.referenced + this + } + + private val validAliasFlags = SUPERACCESSOR | PARAMACCESSOR | MIXEDIN | SPECIALIZED + + override def alias: Symbol = + if (hasFlag(validAliasFlags)) initialize.referenced + else NoSymbol + + def setAlias(alias: Symbol): TermSymbol = { + assert(alias != NoSymbol, this) + assert(!alias.isOverloaded, alias) + assert(hasFlag(validAliasFlags), this) + + referenced = alias + this + } + + override def outerSource: Symbol = + if (name endsWith nme.OUTER) initialize.referenced + else NoSymbol + + override def moduleClass: Symbol = + if (hasFlag(MODULE)) referenced else NoSymbol + + def setModuleClass(clazz: Symbol): TermSymbol = { + assert(hasFlag(MODULE)) + referenced = clazz + this + } + + def setLazyAccessor(sym: Symbol): TermSymbol = { + assert(isLazy && (referenced == NoSymbol || referenced == sym), this) + referenced = sym + this + } + + override def lazyAccessor: Symbol = { + assert(isLazy, this) + referenced + } + + protected def doCookJavaRawInfo() { + def cook(sym: Symbol) { + require(sym hasFlag JAVA) + // @M: I think this is more desirable, but Martin prefers to leave raw-types as-is as much as possible + // object rawToExistentialInJava extends TypeMap { + // def apply(tp: Type): Type = tp match { + // // any symbol that occurs in a java sig, not just java symbols + // // see http://lampsvn.epfl.ch/trac/scala/ticket/2454#comment:14 + // case TypeRef(pre, sym, List()) if !sym.typeParams.isEmpty => + // val eparams = typeParamsToExistentials(sym, sym.typeParams) + // existentialAbstraction(eparams, TypeRef(pre, sym, eparams map (_.tpe))) + // case _ => + // mapOver(tp) + // } + // } + val tpe1 = rawToExistential(sym.tpe) + // println("cooking: "+ sym +": "+ sym.tpe +" to "+ tpe1) + if (tpe1 ne sym.tpe) { + sym.setInfo(tpe1) + } + } + + if (isJavaDefined) + cook(this) + else if (hasFlag(OVERLOADED)) + for (sym2 <- alternatives) + if (sym2 hasFlag JAVA) + cook(sym2) + } + } + + /** A class for module symbols */ + class ModuleSymbol(initOwner: Symbol, initPos: Position, initName: TermName) + extends TermSymbol(initOwner, initPos, initName) { + private var flatname: TermName = null + // This method could use a better name from someone clearer on what the condition expresses. + private def isFlatAdjusted = !isMethod && needsFlatClasses + + override def owner: Symbol = + if (isFlatAdjusted) rawowner.owner + else rawowner + + override def name: TermName = + if (isFlatAdjusted) { + if (flatname == null) + flatname = flattenName().toTermName + + flatname + } else rawname + + override def cloneSymbolImpl(owner: Symbol): Symbol = + new ModuleSymbol(owner, pos, name).copyAttrsFrom(this) + } + + /** A class for method symbols */ + class MethodSymbol(initOwner: Symbol, initPos: Position, initName: TermName) + extends TermSymbol(initOwner, initPos, initName) { + private var mtpePeriod = NoPeriod + private var mtpePre: Type = _ + private var mtpeResult: Type = _ + private var mtpeInfo: Type = _ + + override def cloneSymbolImpl(owner: Symbol): Symbol = + new MethodSymbol(owner, pos, name).copyAttrsFrom(this) + + def typeAsMemberOf(pre: Type): Type = { + if (mtpePeriod == currentPeriod) { + if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult + } else if (isValid(mtpePeriod)) { + mtpePeriod = currentPeriod + if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult + } + val res = pre.computeMemberType(this) + mtpePeriod = currentPeriod + mtpePre = pre + mtpeInfo = info + mtpeResult = res + res + } + } + + /** A class of type symbols. Alias and abstract types are direct instances + * of this class. Classes are instances of a subclass. + */ + class TypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) + extends Symbol(initOwner, initPos, initName) { + privateWithin = NoSymbol + private var tyconCache: Type = null + private var tyconRunId = NoRunId + private var tpeCache: Type = _ + private var tpePeriod = NoPeriod + + override def name: TypeName = super.name.asInstanceOf[TypeName] + final override def isType = true + override def isNonClassType = true + override def isAbstractType = isDeferred + override def isAliasType = !isDeferred + + private def newTypeRef(targs: List[Type]) = { + val pre = if (hasFlag(PARAM | EXISTENTIAL)) NoPrefix else owner.thisType + typeRef(pre, this, targs) + } + + /** Let's say you have a type definition + * + * type T <: Number + * + * and tsym is the symbol corresponding to T. Then + * + * tsym.info = TypeBounds(Nothing, Number) + * tsym.tpe = TypeRef(NoPrefix, T, List()) + */ + override def tpe: Type = { + if (tpeCache eq NoType) throw CyclicReference(this, typeConstructor) + if (tpePeriod != currentPeriod) { + if (isValid(tpePeriod)) { + tpePeriod = currentPeriod + } else { + if (isInitialized) tpePeriod = currentPeriod + tpeCache = NoType + val targs = + if (phase.erasedTypes && this != ArrayClass) List() + else unsafeTypeParams map (_.typeConstructor) //@M! use typeConstructor to generate dummy type arguments, + // sym.tpe should not be called on a symbol that's supposed to be a higher-kinded type + // memberType should be used instead, that's why it uses tpeHK and not tpe + tpeCache = newTypeRef(targs) + } + } + assert(tpeCache ne null/*, "" + this + " " + phase*/)//debug + tpeCache + } + + // needed for experimental code for early types as type parameters + // def refreshType() { tpePeriod = NoPeriod } + + override def typeConstructor: Type = { + if ((tyconCache eq null) || tyconRunId != currentRunId) { + tyconCache = newTypeRef(Nil) + tyconRunId = currentRunId + } + assert(tyconCache ne null) + tyconCache + } + + override def info_=(tp: Type) { + tpePeriod = NoPeriod + tyconCache = null + super.info_=(tp) + } + + override def reset(completer: Type) { + super.reset(completer) + tpePeriod = NoPeriod + tyconRunId = NoRunId + } + + /*** example: + * public class Test3<T> {} + * public class Test1<T extends Test3> {} + * info for T in Test1 should be >: Nothing <: Test3[_] + */ + protected def doCookJavaRawInfo() { + // don't require isJavaDefined, since T in the above example does not have that flag + val tpe1 = rawToExistential(info) + // println("cooking type: "+ this +": "+ info +" to "+ tpe1) + if (tpe1 ne info) { + setInfo(tpe1) + } + } + + def cloneSymbolImpl(owner: Symbol): Symbol = + new TypeSymbol(owner, pos, name) //.toTypeName) + + incCounter(typeSymbolCount) + } + + /** A class for type parameters viewed from inside their scopes + * + * @param origin Can be either a tree, or a symbol, or null. + * If skolem got created from newTypeSkolem (called in Namers), origin denotes + * the type parameter from which the skolem was created. If it got created from + * skolemizeExistential, origin is either null or a Tree. If it is a Tree, it indicates + * where the skolem was introduced (this is important for knowing when to pack it + * again into ab Existential). origin is `null' only in skolemizeExistentials called + * from <:< or isAsSpecific, because here its value does not matter. + * I elieve the following invariant holds: + * + * origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL) + */ + class TypeSkolem(initOwner: Symbol, initPos: Position, initName: TypeName, origin: AnyRef) + extends TypeSymbol(initOwner, initPos, initName) { + + /** The skolemization level in place when the skolem was constructed */ + val level = skolemizationLevel + + final override def isSkolem = true + + /** If typeskolem comes from a type parameter, that parameter, otherwise skolem itself */ + override def deSkolemize = origin match { + case s: Symbol => s + case _ => this + } + + /** If type skolem comes from an existential, the tree where it was created */ + override def unpackLocation = origin + + override def typeParams = info.typeParams //@M! (not deSkolemize.typeParams!!), also can't leave superclass definition: use info, not rawInfo + + override def cloneSymbolImpl(owner: Symbol): Symbol = + new TypeSkolem(owner, pos, name, origin) + + override def nameString: String = + if (settings.debug.value) (super.nameString + "&" + level) + else super.nameString + } + + + /** A class for class symbols */ + class ClassSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) + extends TypeSymbol(initOwner, initPos, initName) { + + private var source: AbstractFile = null + private var thissym: Symbol = this + + final override def isClass = true + final override def isNonClassType = false + final override def isAbstractType = false + final override def isAliasType = false + + override def sourceFile = + if (owner.isPackageClass) source + else super.sourceFile + override def sourceFile_=(f: AbstractFile) { source = f } + + override def reset(completer: Type) { + super.reset(completer) + thissym = this + } + + private var flatname: TypeName = null + + override def owner: Symbol = + if (needsFlatClasses) rawowner.owner + else rawowner + + override def name: TypeName = + if (needsFlatClasses) { + if (flatname == null) + flatname = flattenName().toTypeName + flatname + } + else rawname.asInstanceOf[TypeName] + + private var thisTypeCache: Type = _ + private var thisTypePeriod = NoPeriod + + private var typeOfThisCache: Type = _ + private var typeOfThisPeriod = NoPeriod + + /** the type this.type in this class */ + override def thisType: Type = { + val period = thisTypePeriod + if (period != currentPeriod) { + thisTypePeriod = currentPeriod + if (!isValid(period)) thisTypeCache = ThisType(this) + } + thisTypeCache + } + + /** A symbol carrying the self type of the class as its type */ + override def thisSym: Symbol = thissym + + /** the self type of an object foo is foo.type, not class<foo>.this.type + */ + override def typeOfThis: Type = { + if (getFlag(MODULE | IMPLCLASS) == MODULE.toLong && owner != NoSymbol) { + val period = typeOfThisPeriod + if (period != currentPeriod) { + typeOfThisPeriod = currentPeriod + if (!isValid(period)) + typeOfThisCache = singleType(owner.thisType, sourceModule) + } + typeOfThisCache + } + else thissym.tpe + } + + /** Sets the self type of the class */ + override def typeOfThis_=(tp: Type) { + thissym = newThisSym(pos).setInfo(tp) + } + + override def cloneSymbolImpl(owner: Symbol): Symbol = { + val clone = new ClassSymbol(owner, pos, name) + if (thisSym != this) { + clone.typeOfThis = typeOfThis + clone.thisSym.name = thisSym.name + } + clone + } + + override def sourceModule = + if (isModuleClass) companionModule else NoSymbol + + private var childSet: Set[Symbol] = Set() + override def children = childSet + override def addChild(sym: Symbol) { childSet = childSet + sym } + + incCounter(classSymbolCount) + } + + /** A class for module class symbols + * Note: Not all module classes are of this type; when unpickled, we get + * plain class symbols! + */ + class ModuleClassSymbol(owner: Symbol, pos: Position, name: TypeName) + extends ClassSymbol(owner, pos, name) { + private var module: Symbol = null + def this(module: TermSymbol) = { + this(module.owner, module.pos, module.name.toTypeName) + setFlag(module.getFlag(ModuleToClassFlags) | MODULE | FINAL) + sourceModule = module + } + override def sourceModule = module + private var implicitMembersCacheValue: List[Symbol] = List() + private var implicitMembersCacheKey: Type = NoType + def implicitMembers: List[Symbol] = { + val tp = info + if (implicitMembersCacheKey ne tp) { + implicitMembersCacheKey = tp + implicitMembersCacheValue = tp.implicitMembers + } + implicitMembersCacheValue + } + override def sourceModule_=(module: Symbol) { this.module = module } + } + + /** An object representing a missing symbol */ + object NoSymbol extends Symbol(null, NoPosition, nme.NO_NAME) { + setInfo(NoType) + privateWithin = this + override def info_=(info: Type) { + infos = TypeHistory(1, NoType, null) + unlock() + validTo = currentPeriod + } + override def defString: String = toString + override def locationString: String = "" + override def enclClass: Symbol = this + override def toplevelClass: Symbol = this + override def enclMethod: Symbol = this + override def owner: Symbol = abort("no-symbol does not have owner") + override def sourceFile: AbstractFile = null + override def ownerChain: List[Symbol] = List() + override def ownersIterator: Iterator[Symbol] = Iterator.empty + override def alternatives: List[Symbol] = List() + override def reset(completer: Type) {} + override def info: Type = NoType + override def rawInfo: Type = NoType + protected def doCookJavaRawInfo() {} + override def accessBoundary(base: Symbol): Symbol = RootClass + def cloneSymbolImpl(owner: Symbol): Symbol = abort() + override def originalEnclosingMethod = this + } + + def cloneSymbols[T <: Symbol](syms: List[T]): List[T] = { + val syms1 = syms map (_.cloneSymbol.asInstanceOf[T]) + for (sym1 <- syms1) sym1.setInfo(sym1.info.substSym(syms, syms1)) + syms1 + } + + def cloneSymbols[T <: Symbol](syms: List[T], owner: Symbol): List[T] = { + val syms1 = syms map (_.cloneSymbol(owner).asInstanceOf[T]) + for (sym1 <- syms1) sym1.setInfo(sym1.info.substSym(syms, syms1)) + syms1 + } + + /** An exception for cyclic references of symbol definitions */ + case class CyclicReference(sym: Symbol, info: Type) + extends TypeError("illegal cyclic reference involving " + sym) { + // printStackTrace() // debug + } + + case class InvalidCompanions(sym1: Symbol, sym2: Symbol) + extends Throwable("Companions '" + sym1 + "' and '" + sym2 + "' must be defined in same file") { + override def toString = getMessage + } + + /** A class for type histories */ + private sealed case class TypeHistory(var validFrom: Period, info: Type, prev: TypeHistory) { + assert((prev eq null) || phaseId(validFrom) > phaseId(prev.validFrom), this) + assert(validFrom != NoPeriod) + override def toString() = + "TypeHistory(" + phaseOf(validFrom)+":"+runId(validFrom) + "," + info + "," + prev + ")" + } +} diff --git a/src/compiler/scala/reflect/common/TreeGen.scala b/src/compiler/scala/reflect/common/TreeGen.scala new file mode 100644 index 0000000000..5d43e0f26e --- /dev/null +++ b/src/compiler/scala/reflect/common/TreeGen.scala @@ -0,0 +1,234 @@ +package scala.reflect +package common + +abstract class TreeGen { + val global: SymbolTable + + import global._ + import definitions._ + + def rootId(name: Name) = Select(Ident(nme.ROOTPKG), name) + def rootScalaDot(name: Name) = Select(rootId(nme.scala_) setSymbol ScalaPackage, name) + def scalaDot(name: Name) = Select(Ident(nme.scala_) setSymbol ScalaPackage, name) + def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) + def scalaUnitConstr = scalaDot(tpnme.Unit) + def scalaScalaObjectConstr = scalaDot(tpnme.ScalaObject) + def productConstr = scalaDot(tpnme.Product) + def serializableConstr = scalaDot(tpnme.Serializable) + + def scalaFunctionConstr(argtpes: List[Tree], restpe: Tree, abstractFun: Boolean = false): Tree = { + val cls = if (abstractFun) + mkAttributedRef(AbstractFunctionClass(argtpes.length)) + else + mkAttributedRef(FunctionClass(argtpes.length)) + AppliedTypeTree(cls, argtpes :+ restpe) + } + + /** Builds a reference to value whose type is given stable prefix. + * The type must be suitable for this. For example, it + * must not be a TypeRef pointing to an abstract type variable. + */ + def mkAttributedQualifier(tpe: Type): Tree = + mkAttributedQualifier(tpe, NoSymbol) + + /** Builds a reference to value whose type is given stable prefix. + * If the type is unsuitable, e.g. it is a TypeRef for an + * abstract type variable, then an Ident will be made using + * termSym as the Ident's symbol. In that case, termSym must + * not be NoSymbol. + */ + def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = tpe match { + case NoPrefix => + EmptyTree + case ThisType(clazz) => + if (clazz.isEffectiveRoot) EmptyTree + else mkAttributedThis(clazz) + case SingleType(pre, sym) => + applyIfNoArgs(mkAttributedStableRef(pre, sym)) + case TypeRef(pre, sym, args) => + if (sym.isRoot) { + mkAttributedThis(sym) + } else if (sym.isModuleClass) { + applyIfNoArgs(mkAttributedRef(pre, sym.sourceModule)) + } else if (sym.isModule || sym.isClass) { + assert(phase.erasedTypes, tpe) + mkAttributedThis(sym) + } else if (sym.isType) { + assert(termSym != NoSymbol, tpe) + mkAttributedIdent(termSym) setType tpe + } else { + mkAttributedRef(pre, sym) + } + + case ConstantType(value) => + Literal(value) setType tpe + + case AnnotatedType(_, atp, _) => + mkAttributedQualifier(atp) + + case RefinedType(parents, _) => + // I am unclear whether this is reachable, but + // the following implementation looks logical -Lex + val firstStable = parents.find(_.isStable) + assert(!firstStable.isEmpty, tpe) + mkAttributedQualifier(firstStable.get) + + case _ => + abort("bad qualifier: " + tpe) + } + /** If this is a reference to a method with an empty + * parameter list, wrap it in an apply. + */ + private def applyIfNoArgs(qual: Tree) = qual.tpe match { + case MethodType(Nil, restpe) => Apply(qual, Nil) setType restpe + case _ => qual + } + + /** Builds a reference to given symbol with given stable prefix. */ + def mkAttributedRef(pre: Type, sym: Symbol): Tree = { + val qual = mkAttributedQualifier(pre) + qual match { + case EmptyTree => mkAttributedIdent(sym) + case This(clazz) if qual.symbol.isEffectiveRoot => mkAttributedIdent(sym) + case _ => mkAttributedSelect(qual, sym) + } + } + + /** Builds a reference to given symbol. */ + def mkAttributedRef(sym: Symbol): Tree = + if (sym.owner.isClass) mkAttributedRef(sym.owner.thisType, sym) + else mkAttributedIdent(sym) + + /** Builds an untyped reference to given symbol. */ + def mkUnattributedRef(sym: Symbol): Tree = + if (sym.owner.isClass) Select(This(sym.owner), sym) + else Ident(sym) + + /** Replaces tree type with a stable type if possible */ + def stabilize(tree: Tree): Tree = { + for(tp <- stableTypeFor(tree)) tree.tpe = tp + tree + } + + /** Computes stable type for a tree if possible */ + def stableTypeFor(tree: Tree): Option[Type] = tree match { + case Ident(_) if tree.symbol.isStable => + Some(singleType(tree.symbol.owner.thisType, tree.symbol)) + case Select(qual, _) if ((tree.symbol ne null) && (qual.tpe ne null)) && // turned assert into guard for #4064 + tree.symbol.isStable && qual.tpe.isStable => + Some(singleType(qual.tpe, tree.symbol)) + case _ => + None + } + + /** Cast `tree' to type `pt' */ + def mkCast(tree: Tree, pt: Type): Tree = { + if (settings.debug.value) log("casting " + tree + ":" + tree.tpe + " to " + pt) + assert(!tree.tpe.isInstanceOf[MethodType], tree) + assert(!pt.typeSymbol.isPackageClass) + assert(!pt.typeSymbol.isPackageObjectClass) + assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize)) //@MAT only called during erasure, which already takes care of that + atPos(tree.pos)(mkAsInstanceOf(tree, pt, false)) + } + + /** Builds a reference with stable type to given symbol */ + def mkAttributedStableRef(pre: Type, sym: Symbol): Tree = + stabilize(mkAttributedRef(pre, sym)) + + def mkAttributedStableRef(sym: Symbol): Tree = + stabilize(mkAttributedRef(sym)) + + def mkAttributedThis(sym: Symbol): Tree = + This(sym.name.toTypeName) setSymbol sym setType sym.thisType + + def mkAttributedIdent(sym: Symbol): Tree = + Ident(sym.name) setSymbol sym setType sym.tpe + + def mkAttributedSelect(qual: Tree, sym: Symbol): Tree = { + // Tests involving the repl fail without the .isEmptyPackage condition. + if (qual.symbol != null && (qual.symbol.isEffectiveRoot || qual.symbol.isEmptyPackage)) + mkAttributedIdent(sym) + else { + val pkgQualifier = + if (sym != null && sym.owner.isPackageObjectClass && sym.owner.owner == qual.tpe.typeSymbol) { + val obj = sym.owner.sourceModule + Select(qual, nme.PACKAGEkw) setSymbol obj setType singleType(qual.tpe, obj) + } + else qual + + val tree = Select(pkgQualifier, sym) + if (pkgQualifier.tpe == null) tree + else tree setType (qual.tpe memberType sym) + } + } + + private def mkTypeApply(value: Tree, tpe: Type, what: Symbol) = + Apply( + TypeApply( + mkAttributedSelect(value, what), + List(TypeTree(tpe.normalize)) + ), + Nil + ) + /** Builds an instance test with given value and type. */ + def mkIsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree = + mkTypeApply(value, tpe, (if (any) Any_isInstanceOf else Object_isInstanceOf)) + + /** Builds a cast with given value and type. */ + def mkAsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree = + mkTypeApply(value, tpe, (if (any) Any_asInstanceOf else Object_asInstanceOf)) + + /** Cast `tree' to 'pt', unless tpe is a subtype of pt, or pt is Unit. */ + def maybeMkAsInstanceOf(tree: Tree, pt: Type, tpe: Type, beforeRefChecks: Boolean = false): Tree = + if ((pt == UnitClass.tpe) || (tpe <:< pt)) { + log("no need to cast from " + tpe + " to " + pt) + tree + } else + atPos(tree.pos) { + if (beforeRefChecks) + TypeApply(mkAttributedSelect(tree, Any_asInstanceOf), List(TypeTree(pt))) + else + mkAsInstanceOf(tree, pt) + } + + def mkClassOf(tp: Type): Tree = + Literal(Constant(tp)) setType ConstantType(Constant(tp))// ClassType(tp) + + /** Builds a list with given head and tail. */ + def mkNewCons(head: Tree, tail: Tree): Tree = + New(Apply(mkAttributedRef(ConsClass), List(head, tail))) + + /** Builds a list with given head and tail. */ + def mkNil: Tree = mkAttributedRef(NilModule) + + /** Builds a tree representing an undefined local, as in + * var x: T = _ + * which is appropriate to the given Type. + */ + def mkZero(tp: Type): Tree = { + val sym = tp.typeSymbol + val tree = + if (sym == UnitClass) Literal(()) + else if (sym == BooleanClass) Literal(false) + else if (isValueClass(sym)) Literal(0) + else if (NullClass.tpe <:< tp) Literal(null: Any) + else abort("Cannot determine zero for " + tp) + + tree setType tp + } + + /** Builds a tuple */ + def mkTuple(elems: List[Tree]): Tree = + if (elems.isEmpty) Literal(()) + else Apply( + Select(mkAttributedRef(TupleClass(elems.length).caseModule), nme.apply), + elems) + + // tree1 AND tree2 + def mkAnd(tree1: Tree, tree2: Tree): Tree = + Apply(Select(tree1, Boolean_and), List(tree2)) + + // tree1 OR tree2 + def mkOr(tree1: Tree, tree2: Tree): Tree = + Apply(Select(tree1, Boolean_or), List(tree2)) +}
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/reflect/common/TreeInfo.scala index 5184ebad19..95189d1813 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/reflect/common/TreeInfo.scala @@ -3,11 +3,10 @@ * @author Martin Odersky */ -package scala.tools.nsc -package ast +package scala.reflect +package common -import symtab.Flags._ -import symtab.SymbolTable +import Flags._ import util.HashSet /** This class ... @@ -356,7 +355,6 @@ abstract class TreeInfo { || containsLeadingPredefImport(List(body))) } - def isAbsTypeDef(tree: Tree) = tree match { case TypeDef(_, _, _, TypeBoundsTree(_, _)) => true case TypeDef(_, _, _, rhs) => rhs.tpe.isInstanceOf[TypeBounds] diff --git a/src/compiler/scala/reflect/common/TreePrinters.scala b/src/compiler/scala/reflect/common/TreePrinters.scala new file mode 100644 index 0000000000..711232d774 --- /dev/null +++ b/src/compiler/scala/reflect/common/TreePrinters.scala @@ -0,0 +1,461 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +import java.io.{ OutputStream, PrintWriter, StringWriter, Writer } +import Flags._ + +trait TreePrinters { self: SymbolTable => + + //nsc import treeInfo.{ IsTrue, IsFalse } + + final val showOuterTests = false + + /** Adds backticks if the name is a scala keyword. */ + def quotedName(name: Name, decode: Boolean): String = { + val s = if (decode) name.decode else name.toString + val term = name.toTermName + if (nme.keywords(term) && term != nme.USCOREkw) "`%s`" format s + else s + } + def quotedName(name: Name): String = quotedName(name, false) + + /** Turns a path into a String, introducing backquotes + * as necessary. + */ + def backquotedPath(t: Tree): String = t match { + case Select(qual, name) => "%s.%s".format(backquotedPath(qual), quotedName(name)) + case Ident(name) => quotedName(name) + case _ => t.toString + } + + class TreePrinter(out: PrintWriter) { + protected var indentMargin = 0 + protected val indentStep = 2 + protected var indentString = " " // 40 + + def flush() = out.flush() + + def indent() = indentMargin += indentStep + def undent() = indentMargin -= indentStep + + protected def doPrintPositions = settings.Xprintpos.value + def printPosition(tree: Tree) = if (doPrintPositions) print(showPos(tree.pos)) + + def println() { + out.println() + while (indentMargin > indentString.length()) + indentString += indentString + if (indentMargin > 0) + out.write(indentString, 0, indentMargin) + } + + def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) { + ls match { + case List() => + case List(x) => printelem(x) + case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep) + } + } + + def printColumn(ts: List[Tree], start: String, sep: String, end: String) { + print(start); indent; println() + printSeq(ts){print}{print(sep); println()}; undent; println(); print(end) + } + + def printRow(ts: List[Tree], start: String, sep: String, end: String) { + print(start); printSeq(ts){print}{print(sep)}; print(end) + } + + def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") } + + def printTypeParams(ts: List[TypeDef]) { + if (!ts.isEmpty) { + print("["); printSeq(ts){ t => + printAnnotations(t) + printParam(t) + }{print(", ")}; print("]") + } + } + + def printValueParams(ts: List[ValDef]) { + print("(") + if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "") + printSeq(ts){printParam}{print(", ")} + print(")") + } + + def printParam(tree: Tree) { + tree match { + case ValDef(mods, name, tp, rhs) => + printPosition(tree) + printAnnotations(tree) + print(symName(tree, name)); printOpt(": ", tp); printOpt(" = ", rhs) + case TypeDef(mods, name, tparams, rhs) => + printPosition(tree) + print(symName(tree, name)) + printTypeParams(tparams); print(rhs) + } + } + + def printBlock(tree: Tree) { + tree match { + case Block(_, _) => + print(tree) + case _ => + printColumn(List(tree), "{", ";", "}") + } + } + + private def symFn[T](tree: Tree, f: Symbol => T, orElse: => T): T = tree.symbol match { + case null | NoSymbol => orElse + case sym => f(sym) + } + private def ifSym(tree: Tree, p: Symbol => Boolean) = symFn(tree, p, false) + + private def symNameInternal(tree: Tree, name: Name, decoded: Boolean): String = { + def nameFn(sym: Symbol) = { + val prefix = if (sym.isMixinConstructor) "/*%s*/".format(quotedName(sym.owner.name, decoded)) else "" + prefix + tree.symbol.nameString + } + symFn(tree, nameFn, quotedName(name, decoded)) + } + + def decodedSymName(tree: Tree, name: Name) = symNameInternal(tree, name, true) + def symName(tree: Tree, name: Name) = symNameInternal(tree, name, false) + + def printOpt(prefix: String, tree: Tree) { + if (!tree.isEmpty) { print(prefix); print(tree) } + } + + def printModifiers(tree: Tree, mods: Modifiers): Unit = printFlags( + if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + ( + if (tree.symbol == NoSymbol) mods.privateWithin + else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name + else "" + ) + ) + + def printFlags(flags: Long, privateWithin: String) { + var mask: Long = if (settings.debug.value) -1L else PrintableFlags + val s = flagsToString(flags & mask, privateWithin) + if (s != "") print(s + " ") + } + + def printAnnotations(tree: Tree) { + val annots = + if (tree.symbol.hasAssignedAnnotations) tree.symbol.annotations + else tree.asInstanceOf[MemberDef].mods.annotations + + annots foreach (annot => print("@"+annot+" ")) + } + + def print(str: String) { out.print(str) } + def print(name: Name) { print(quotedName(name)) } + + private var currentOwner: Symbol = NoSymbol + private var selectorType: Type = NoType + + def printRaw(tree: Tree) { + tree match { + case EmptyTree => + print("<empty>") + + case ClassDef(mods, name, tparams, impl) => + printAnnotations(tree) + printModifiers(tree, mods) + val word = + if (mods.hasTraitFlag) "trait" + else if (ifSym(tree, _.isModuleClass)) "object" + else "class" + + print(word + " " + symName(tree, name)) + printTypeParams(tparams) + print(if (mods.isDeferred) " <: " else " extends "); print(impl) + + case PackageDef(packaged, stats) => + printAnnotations(tree) + print("package "); print(packaged); printColumn(stats, " {", ";", "}") + + case ModuleDef(mods, name, impl) => + printAnnotations(tree) + printModifiers(tree, mods); print("object " + symName(tree, name)) + print(" extends "); print(impl) + + case ValDef(mods, name, tp, rhs) => + printAnnotations(tree) + printModifiers(tree, mods) + print(if (mods.isMutable) "var " else "val ") + print(symName(tree, name)) + printOpt(": ", tp) + if (!mods.isDeferred) { + print(" = ") + if (rhs.isEmpty) print("_") else print(rhs) + } + + case DefDef(mods, name, tparams, vparamss, tp, rhs) => + printAnnotations(tree) + printModifiers(tree, mods) + print("def " + symName(tree, name)) + printTypeParams(tparams); vparamss foreach printValueParams + printOpt(": ", tp); printOpt(" = ", rhs) + + case TypeDef(mods, name, tparams, rhs) => + if (mods hasFlag (PARAM | DEFERRED)) { + printAnnotations(tree) + printModifiers(tree, mods); print("type "); printParam(tree) + } else { + printAnnotations(tree) + printModifiers(tree, mods); print("type " + symName(tree, name)) + printTypeParams(tparams); printOpt(" = ", rhs) + } + + case LabelDef(name, params, rhs) => + print(symName(tree, name)); printRow(params, "(", ",", ")"); printBlock(rhs) + + case Import(expr, selectors) => + // Is this selector remapping a name (i.e, {name1 => name2}) + def isNotRemap(s: ImportSelector) : Boolean = (s.name == nme.WILDCARD || s.name == s.rename) + def selectorToString(s: ImportSelector): String = { + val from = quotedName(s.name) + if (isNotRemap(s)) from + else from + "=>" + quotedName(s.rename) + } + print("import "); print(backquotedPath(expr)) + print(".") + selectors match { + case List(s) => + // If there is just one selector and it is not remapping a name, no braces are needed + if (isNotRemap(s)) { + print(selectorToString(s)) + } else { + print("{"); print(selectorToString(s)); print("}") + } + // If there is more than one selector braces are always needed + case many => + print(many.map(selectorToString).mkString("{", ", ", "}")) + } + + case DocDef(comment, definition) => + print(comment.raw); println(); print(definition) + + case Template(parents, self, body) => + val currentOwner1 = currentOwner + if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner + printRow(parents, " with ") + if (!body.isEmpty) { + if (self.name != nme.WILDCARD) { + print(" { "); print(self.name); printOpt(": ", self.tpt); print(" => ") + } else if (!self.tpt.isEmpty) { + print(" { _ : "); print(self.tpt); print(" => ") + } else { + print(" {") + } + printColumn(body, "", ";", "}") + } + currentOwner = currentOwner1 + + case Block(stats, expr) => + printColumn(stats ::: List(expr), "{", ";", "}") + + case Match(selector, cases) => + val selectorType1 = selectorType + selectorType = selector.tpe + print(selector); printColumn(cases, " match {", "", "}") + selectorType = selectorType1 + + case CaseDef(pat, guard, body) => + print("case ") + def patConstr(pat: Tree): Tree = pat match { + case Apply(fn, args) => patConstr(fn) + case _ => pat + } + if (showOuterTests && + needsOuterTest( + patConstr(pat).tpe.finalResultType, selectorType, currentOwner)) + print("???") + print(pat); printOpt(" if ", guard) + print(" => "); print(body) + + case Alternative(trees) => + printRow(trees, "(", "| ", ")") + + case Star(elem) => + print("("); print(elem); print(")*") + + case Bind(name, t) => + print("("); print(symName(tree, name)); print(" @ "); print(t); print(")") + + case UnApply(fun, args) => + print(fun); print(" <unapply> "); printRow(args, "(", ", ", ")") + + case ArrayValue(elemtpt, trees) => + print("Array["); print(elemtpt); printRow(trees, "]{", ", ", "}") + + case Function(vparams, body) => + print("("); printValueParams(vparams); print(" => "); print(body); print(")") + if (settings.uniqid.value && tree.symbol != null) print("#"+tree.symbol.id) + + case Assign(lhs, rhs) => + print(lhs); print(" = "); print(rhs) + + case AssignOrNamedArg(lhs, rhs) => + print(lhs); print(" = "); print(rhs) + + case If(cond, thenp, elsep) => + print("if ("); print(cond); print(")"); indent; println() + print(thenp); undent + if (!elsep.isEmpty) { + println(); print("else"); indent; println(); print(elsep); undent + } + + case Return(expr) => + print("return "); print(expr) + + case Try(block, catches, finalizer) => + print("try "); printBlock(block) + if (!catches.isEmpty) printColumn(catches, " catch {", "", "}") + printOpt(" finally ", finalizer) + + case Throw(expr) => + print("throw "); print(expr) + + case New(tpe) => + print("new "); print(tpe) + + case Typed(expr, tp) => + print("("); print(expr); print(": "); print(tp); print(")") + + case TypeApply(fun, targs) => + print(fun); printRow(targs, "[", ", ", "]") + + case Apply(fun, vargs) => + print(fun); printRow(vargs, "(", ", ", ")") + + case ApplyDynamic(qual, vargs) => + print("<apply-dynamic>("); print(qual); print("#"); print(tree.symbol.nameString) + printRow(vargs, ", (", ", ", "))") + + case Super(This(qual), mix) => + if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".") + print("super") + if (!mix.isEmpty) + print("[" + mix + "]") + + case Super(qual, mix) => + print(qual) + print(".super") + if (!mix.isEmpty) + print("[" + mix + "]") + + case This(qual) => + if (!qual.isEmpty) print(symName(tree, qual) + ".") + print("this") + + case Select(qual @ New(tpe), name) if (!settings.debug.value) => + print(qual) + + case Select(qualifier, name) => + print(backquotedPath(qualifier)); print("."); print(symName(tree, name)) + + case Ident(name) => + print(symName(tree, name)) + + case Literal(x) => + print(x.escapedStringValue) + + case tt: TypeTree => + if ((tree.tpe eq null) || (settings.Xprintpos.value && tt.original != null)) { + if (tt.original != null) { print("<type: "); print(tt.original); print(">") } + else print("<type ?>") + } else if ((tree.tpe.typeSymbol ne null) && tree.tpe.typeSymbol.isAnonymousClass) { + print(tree.tpe.typeSymbol.toString()) + } else { + print(tree.tpe.toString()) + } + + case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) => + def printAnnot() { + print("@"); print(tpt) + if (!args.isEmpty) + printRow(args, "(", ",", ")") + } + if (tree.isType) { print(tree); print(" "); printAnnot() } + else { print(tree); print(": "); printAnnot() } + + case SingletonTypeTree(ref) => + print(ref); print(".type") + + case SelectFromTypeTree(qualifier, selector) => + print(qualifier); print("#"); print(symName(tree, selector)) + + case CompoundTypeTree(templ) => + print(templ) + + case AppliedTypeTree(tp, args) => + print(tp); printRow(args, "[", ", ", "]") + + case TypeBoundsTree(lo, hi) => + printOpt(" >: ", lo); printOpt(" <: ", hi) + + case ExistentialTypeTree(tpt, whereClauses) => + print(tpt); + printColumn(whereClauses, " forSome { ", ";", "}") + + case SelectFromArray(qualifier, name, _) => + print(qualifier); print(".<arr>"); print(symName(tree, name)) + + case TypeTreeWithDeferredRefCheck() => + print("<tree with deferred refcheck>") + + case tree => + print("<unknown tree of class "+tree.getClass+">") + } + if (settings.printtypes.value && tree.isTerm && !tree.isEmpty) { + print("{"); print(if (tree.tpe eq null) "<null>" else tree.tpe.toString()); print("}") + } + } + + def print(tree: Tree) { + printPosition(tree) + printRaw( + //nsc if (tree.isDef && tree.symbol != NoSymbol && tree.symbol.isInitialized) { + //nsc tree match { + //nsc case ClassDef(_, _, _, impl @ Template(ps, emptyValDef, body)) + //nsc if (tree.symbol.thisSym != tree.symbol) => + //nsc ClassDef(tree.symbol, Template(ps, ValDef(tree.symbol.thisSym), body)) + //nsc case ClassDef(_, _, _, impl) => ClassDef(tree.symbol, impl) + //nsc case ModuleDef(_, _, impl) => ModuleDef(tree.symbol, impl) + //nsc case ValDef(_, _, _, rhs) => ValDef(tree.symbol, rhs) + //nsc case DefDef(_, _, _, vparamss, _, rhs) => DefDef(tree.symbol, vparamss, rhs) + //nsc case TypeDef(_, _, _, rhs) => TypeDef(tree.symbol, rhs) + //nsc case _ => tree + //nsc } + //nsc } else + tree) + } + } + + def newTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer) + def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream)) + def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter)) + + /** A writer that writes to the current Console and + * is sensitive to replacement of the Console's + * output stream. + */ + object ConsoleWriter extends Writer { + override def write(str: String) { Console.print(str) } + + def write(cbuf: Array[Char], off: Int, len: Int) { + write(new String(cbuf, off, len)) + } + + def close = { /* do nothing */ } + def flush = { /* do nothing */ } + } +} diff --git a/src/compiler/scala/reflect/common/Trees.scala b/src/compiler/scala/reflect/common/Trees.scala new file mode 100644 index 0000000000..f7008d7a65 --- /dev/null +++ b/src/compiler/scala/reflect/common/Trees.scala @@ -0,0 +1,1823 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +import scala.collection.mutable.ListBuffer +import Flags._ +import util.HashSet +import java.io.{ PrintWriter, StringWriter } +import Flags._ + +//import scala.tools.nsc.util.{ FreshNameCreator, HashSet, SourceFile } + +trait Trees /*extends reflect.generic.Trees*/ { self: SymbolTable => + + type DocComment <: { def raw: String } + + private[scala] var nodeCount = 0 + + object treeInfo extends { + val trees: Trees.this.type = self + } with TreeInfo + + /** @param privateWithin the qualifier for a private (a type name) + * or tpnme.EMPTY, if none is given. + * @param annotations the annotations for the definition. + * <strong>Note:</strong> the typechecker drops these annotations, + * use the AnnotationInfo's (Symbol.annotations) in later phases. + */ + case class Modifiers(flags: Long, privateWithin: Name, annotations: List[Tree], positions: Map[Long, Position]) extends HasFlags { + /* Abstract types from HasFlags. */ + type FlagsType = Long + type AccessBoundaryType = Name + type AnnotationType = Tree + + def hasAccessBoundary = privateWithin != tpnme.EMPTY + def hasAllFlags(mask: Long): Boolean = (flags & mask) == mask + def hasFlag(flag: Long) = (flag & flags) != 0L + def hasFlagsToString(mask: Long): String = flagsToString( + flags & mask, + if (hasAccessBoundary) privateWithin.toString else "" + ) + def & (flag: Long): Modifiers = { + val flags1 = flags & flag + if (flags1 == flags) this + else Modifiers(flags1, privateWithin, annotations, positions) + } + def &~ (flag: Long): Modifiers = { + val flags1 = flags & (~flag) + if (flags1 == flags) this + else Modifiers(flags1, privateWithin, annotations, positions) + } + def | (flag: Long): Modifiers = { + val flags1 = flags | flag + if (flags1 == flags) this + else Modifiers(flags1, privateWithin, annotations, positions) + } + def withAnnotations(annots: List[Tree]) = + if (annots.isEmpty) this + else copy(annotations = annotations ::: annots) + def withPosition(flag: Long, position: Position) = + copy(positions = positions + (flag -> position)) + + override def toString = "Modifiers(%s, %s, %s)".format(hasFlagsToString(-1L), annotations mkString ", ", positions) + } + + def Modifiers(flags: Long, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List(), Map.empty) + def Modifiers(flags: Long): Modifiers = Modifiers(flags, tpnme.EMPTY) + + lazy val NoMods = Modifiers(0) + + // ------ tree base classes -------------------------------------------------- + + /** The base class for all trees */ + abstract class Tree extends Product { + val id = nodeCount + nodeCount += 1 + + private[this] var rawpos: Position = NoPosition + + def pos = rawpos + def pos_=(pos: Position) = rawpos = pos + def setPos(pos: Position): this.type = { rawpos = pos; this } + + private[this] var rawtpe: Type = _ + + def tpe = rawtpe + def tpe_=(t: Type) = rawtpe = t + + /** Set tpe to give `tp` and return this. + */ + def setType(tp: Type): this.type = { rawtpe = tp; this } + + /** Like `setType`, but if this is a previously empty TypeTree + * that fact is remembered so that resetType will snap back. + */ + def defineType(tp: Type): this.type = setType(tp) + + def symbol: Symbol = null + def symbol_=(sym: Symbol) { throw new UnsupportedOperationException("symbol_= inapplicable for " + this) } + def setSymbol(sym: Symbol): this.type = { symbol = sym; this } + + def hasSymbol = false + def isDef = false + def isEmpty = false + + def hasSymbolWhich(f: Symbol => Boolean) = hasSymbol && f(symbol) + + def isTerm: Boolean = this match { + case _: TermTree => true + case Bind(name, _) => name.isTermName + case Select(_, name) => name.isTermName + case Ident(name) => name.isTermName + case Annotated(_, arg) => arg.isTerm + case DocDef(_, defn) => defn.isTerm + case _ => false + } + + def isType: Boolean = this match { + case _: TypTree => true + case Bind(name, _) => name.isTypeName + case Select(_, name) => name.isTypeName + case Ident(name) => name.isTypeName + case Annotated(_, arg) => arg.isType + case DocDef(_, defn) => defn.isType + case _ => false + } + + def isErroneous = (this.tpe ne null) && this.tpe.isErroneous + def isTyped = (this.tpe ne null) && !this.tpe.isErroneous + + /** Apply `f' to each subtree */ + def foreach(f: Tree => Unit) { new ForeachTreeTraverser(f).traverse(this) } + + /** If 'pf' is defined for a given subtree, call super.traverse(pf(tree)), + * otherwise super.traverse(tree). + */ + def foreachPartial(pf: PartialFunction[Tree, Tree]) { new ForeachPartialTreeTraverser(pf).traverse(this) } + + /** Find all subtrees matching predicate `p' */ + def filter(f: Tree => Boolean): List[Tree] = { + val ft = new FilterTreeTraverser(f) + ft.traverse(this) + ft.hits.toList + } + + /** Returns optionally first tree (in a preorder traversal) which satisfies predicate `p', + * or None if none exists. + */ + def find(p: Tree => Boolean): Option[Tree] = { + val ft = new FindTreeTraverser(p) + ft.traverse(this) + ft.result + } + + def changeOwner(pairs: (Symbol, Symbol)*): Tree = { + pairs.foldLeft(this) { case (t, (oldOwner, newOwner)) => + new ChangeOwnerTraverser(oldOwner, newOwner) apply t + } + } + + /** Is there part of this tree which satisfies predicate `p'? */ + def exists(p: Tree => Boolean): Boolean = !find(p).isEmpty + + def equalsStructure(that : Tree) = equalsStructure0(that)(_ eq _) + def equalsStructure0(that: Tree)(f: (Tree,Tree) => Boolean): Boolean = + f(this, that) || ((this.productArity == that.productArity) && { + def equals0(this0: Any, that0: Any): Boolean = (this0, that0) match { + case (x: Tree, y: Tree) => f(x, y) || (x equalsStructure0 y)(f) + case (xs: List[_], ys: List[_]) => (xs corresponds ys)(equals0) + case _ => this0 == that0 + } + def compareOriginals() = (this, that) match { + case (x: TypeTree, y: TypeTree) if x.original != null && y.original != null => + (x.original equalsStructure0 y.original)(f) + case _ => + true + } + + (this.productIterator zip that.productIterator forall { case (x, y) => equals0(x, y) }) && compareOriginals() + }) + + def shallowDuplicate: Tree = new ShallowDuplicator(this) transform this + def shortClass: String = this.getClass.getName split "[.$]" last + + /** The direct child trees of this tree + * EmptyTrees are always omitted. Lists are collapsed. + */ + def children: List[Tree] = { + def subtrees(x: Any): List[Tree] = x match { + case EmptyTree => Nil + case t: Tree => List(t) + case xs: List[_] => xs flatMap subtrees + case _ => Nil + } + productIterator.toList flatMap subtrees + } + + /** Make a copy of this tree, keeping all attributes, + * except that all positions are focused (so nothing + * in this tree will be found when searching by position). + */ + private[scala] def duplicate: this.type = + duplicateTree(this).asInstanceOf[this.type] + + private[scala] def copyAttrs(tree: Tree): this.type = { + pos = tree.pos + tpe = tree.tpe + if (hasSymbol) symbol = tree.symbol + this + } + + override def toString(): String = { + val buffer = new StringWriter() + val printer = newTreePrinter(new PrintWriter(buffer)) + printer.print(this) + printer.flush() + buffer.toString + } + + override def hashCode(): Int = System.identityHashCode(this) + override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] + } + + trait SymTree extends Tree { + override def hasSymbol = true + override var symbol: Symbol = NoSymbol + } + + trait RefTree extends SymTree { + def name: Name + } + + abstract class DefTree extends SymTree { + def name: Name + override def isDef = true + } + + trait TermTree extends Tree + + /** A tree for a type. Note that not all type trees implement + * this trait; in particular, Ident's are an exception. */ + trait TypTree extends Tree + +// ----- tree node alternatives -------------------------------------- + + /** The empty tree */ + case object EmptyTree extends TermTree { + super.tpe_=(NoType) + override def tpe_=(t: Type) = + if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>") + override def isEmpty = true + } + + abstract class MemberDef extends DefTree { + def mods: Modifiers + def keyword: String = this match { + case TypeDef(_, _, _, _) => "type" + case ClassDef(mods, _, _, _) => if (mods hasFlag TRAIT) "trait" else "class" + case DefDef(_, _, _, _, _, _) => "def" + case ModuleDef(_, _, _) => "object" + case PackageDef(_, _) => "package" + case ValDef(mods, _, _, _) => if (mods.isMutable) "var" else "val" + case _ => "" + } + // final def hasFlag(mask: Long): Boolean = mods hasFlag mask + } + + /** Package clause + */ + case class PackageDef(pid: RefTree, stats: List[Tree]) + extends MemberDef { + def name = pid.name + def mods = NoMods + } + + abstract class ImplDef extends MemberDef { + def impl: Template + } + + /** Class definition */ + case class ClassDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], impl: Template) + extends ImplDef + + /** Singleton object definition + */ + case class ModuleDef(mods: Modifiers, name: TermName, impl: Template) + extends ImplDef + + abstract class ValOrDefDef extends MemberDef { + def name: TermName + def tpt: Tree + def rhs: Tree + } + + /** Value definition + */ + case class ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) extends ValOrDefDef + + /** Method definition + */ + case class DefDef(mods: Modifiers, name: TermName, tparams: List[TypeDef], + vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) extends ValOrDefDef + + /** Abstract type, type parameter, or type alias */ + case class TypeDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree) + extends MemberDef + + /** <p> + * Labelled expression - the symbols in the array (must be Idents!) + * are those the label takes as argument + * </p> + * <p> + * The symbol that is given to the labeldef should have a MethodType + * (as if it were a nested function) + * </p> + * <p> + * Jumps are apply nodes attributed with label symbol, the arguments + * will get assigned to the idents. + * </p> + * <p> + * Note: on 2005-06-09 Martin, Iuli, Burak agreed to have forward + * jumps within a Block. + * </p> + */ + case class LabelDef(name: TermName, params: List[Ident], rhs: Tree) + extends DefTree with TermTree + + + /** Import selector + * + * Representation of an imported name its optional rename and their optional positions + * + * @param name the imported name + * @param namePos its position or -1 if undefined + * @param rename the name the import is renamed to (== name if no renaming) + * @param renamePos the position of the rename or -1 if undefined + */ + case class ImportSelector(name: Name, namePos: Int, rename: Name, renamePos: Int) + + /** Import clause + * + * @param expr + * @param selectors + */ + case class Import(expr: Tree, selectors: List[ImportSelector]) + extends SymTree + // The symbol of an Import is an import symbol @see Symbol.newImport + // It's used primarily as a marker to check that the import has been typechecked. + + /** Instantiation template of a class or trait + * + * @param parents + * @param body + */ + case class Template(parents: List[Tree], self: ValDef, body: List[Tree]) + extends SymTree { + // the symbol of a template is a local dummy. @see Symbol.newLocalDummy + // the owner of the local dummy is the enclosing trait or class. + // the local dummy is itself the owner of any local blocks + // For example: + // + // class C { + // def foo // owner is C + // { + // def bar // owner is local dummy + // } + // System.err.println("TEMPLATE: " + parents) + } + + /** Block of expressions (semicolon separated expressions) */ + case class Block(stats: List[Tree], expr: Tree) + extends TermTree + + /** Case clause in a pattern match, eliminated during explicitouter + * (except for occurrences in switch statements) + */ + case class CaseDef(pat: Tree, guard: Tree, body: Tree) + extends Tree + + /** Alternatives of patterns, eliminated by explicitouter, except for + * occurrences in encoded Switch stmt (=remaining Match(CaseDef(...)) + */ + case class Alternative(trees: List[Tree]) + extends TermTree + + /** Repetition of pattern, eliminated by explicitouter */ + case class Star(elem: Tree) + extends TermTree + + /** Bind of a variable to a rhs pattern, eliminated by explicitouter + * + * @param name + * @param body + */ + case class Bind(name: Name, body: Tree) + extends DefTree + + case class UnApply(fun: Tree, args: List[Tree]) + extends TermTree + + /** Array of expressions, needs to be translated in backend, + */ + case class ArrayValue(elemtpt: Tree, elems: List[Tree]) + extends TermTree + + /** Anonymous function, eliminated by analyzer */ + case class Function(vparams: List[ValDef], body: Tree) + extends TermTree with SymTree + // The symbol of a Function is a synthetic value of name nme.ANON_FUN_NAME + // It is the owner of the function's parameters. + + /** Assignment */ + case class Assign(lhs: Tree, rhs: Tree) + extends TermTree + + /** Conditional expression */ + case class If(cond: Tree, thenp: Tree, elsep: Tree) + extends TermTree + + /** <p> + * Pattern matching expression (before explicitouter) + * Switch statements (after explicitouter) + * </p> + * <p> + * After explicitouter, cases will satisfy the following constraints: + * </p> + * <ul> + * <li>all guards are EmptyTree,</li> + * <li>all patterns will be either <code>Literal(Constant(x:Int))</code> + * or <code>Alternative(lit|...|lit)</code></li> + * <li>except for an "otherwise" branch, which has pattern + * <code>Ident(nme.WILDCARD)</code></li> + * </ul> + */ + case class Match(selector: Tree, cases: List[CaseDef]) + extends TermTree + + /** Return expression */ + case class Return(expr: Tree) + extends TermTree with SymTree + // The symbol of a Return node is the enclosing method. + + case class Try(block: Tree, catches: List[CaseDef], finalizer: Tree) + extends TermTree + + /** Throw expression */ + case class Throw(expr: Tree) + extends TermTree + + /** Object instantiation + * One should always use factory method below to build a user level new. + * + * @param tpt a class type + */ + case class New(tpt: Tree) extends TermTree + + /** Type annotation, eliminated by explicit outer */ + case class Typed(expr: Tree, tpt: Tree) + extends TermTree + + // Martin to Sean: Should GenericApply/TypeApply/Apply not be SymTree's? After all, + // ApplyDynamic is a SymTree. + abstract class GenericApply extends TermTree { + val fun: Tree + val args: List[Tree] + } + + /** Type application */ + case class TypeApply(fun: Tree, args: List[Tree]) + extends GenericApply { + override def symbol: Symbol = fun.symbol + override def symbol_=(sym: Symbol) { fun.symbol = sym } + } + + /** Value application */ + case class Apply(fun: Tree, args: List[Tree]) + extends GenericApply { + override def symbol: Symbol = fun.symbol + override def symbol_=(sym: Symbol) { fun.symbol = sym } + } + + /** Dynamic value application. + * In a dynamic application q.f(as) + * - q is stored in qual + * - as is stored in args + * - f is stored as the node's symbol field. + */ + case class ApplyDynamic(qual: Tree, args: List[Tree]) + extends TermTree with SymTree + // The symbol of an ApplyDynamic is the function symbol of `qual', or NoSymbol, if there is none. + + /** Super reference, qual = corresponding this reference */ + case class Super(qual: Tree, mix: TypeName) extends TermTree { + // The symbol of a Super is the class _from_ which the super reference is made. + // For instance in C.super(...), it would be C. + override def symbol: Symbol = qual.symbol + override def symbol_=(sym: Symbol) { qual.symbol = sym } + } + + /** Self reference */ + case class This(qual: TypeName) + extends TermTree with SymTree + // The symbol of a This is the class to which the this refers. + // For instance in C.this, it would be C. + + /** Designator <qualifier> . <name> */ + case class Select(qualifier: Tree, name: Name) + extends RefTree + + /** Identifier <name> */ + case class Ident(name: Name) extends RefTree { } + + class BackQuotedIdent(name: Name) extends Ident(name) + + /** Literal */ + case class Literal(value: Constant) + extends TermTree { + assert(value ne null) + } + + def Literal(value: Any): Literal = + Literal(Constant(value)) + + /** A tree that has an annotation attached to it. Only used for annotated types and + * annotation ascriptions, annotations on definitions are stored in the Modifiers. + * Eliminated by typechecker (typedAnnotated), the annotations are then stored in + * an AnnotatedType. + */ + case class Annotated(annot: Tree, arg: Tree) extends Tree + + /** Singleton type, eliminated by RefCheck */ + case class SingletonTypeTree(ref: Tree) + extends TypTree + + /** Type selection <qualifier> # <name>, eliminated by RefCheck */ + case class SelectFromTypeTree(qualifier: Tree, name: TypeName) + extends TypTree with RefTree + + /** Intersection type <parent1> with ... with <parentN> { <decls> }, eliminated by RefCheck */ + case class CompoundTypeTree(templ: Template) + extends TypTree + + /** Applied type <tpt> [ <args> ], eliminated by RefCheck */ + case class AppliedTypeTree(tpt: Tree, args: List[Tree]) + extends TypTree { + override def symbol: Symbol = tpt.symbol + override def symbol_=(sym: Symbol) { tpt.symbol = sym } + } + + case class TypeBoundsTree(lo: Tree, hi: Tree) + extends TypTree + + case class ExistentialTypeTree(tpt: Tree, whereClauses: List[Tree]) + extends TypTree + + /** Array selection <qualifier> . <name> only used during erasure */ + case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type) + extends TermTree with RefTree { } + + /** A synthetic tree holding an arbitrary type. Not to be confused with + * with TypTree, the trait for trees that are only used for type trees. + * TypeTree's are inserted in several places, but most notably in + * <code>RefCheck</code>, where the arbitrary type trees are all replaced by + * TypeTree's. */ + case class TypeTree() extends TypTree { + private var orig: Tree = null + private[Trees] var wasEmpty: Boolean = false + + override def symbol = if (tpe == null) null else tpe.typeSymbol + override def isEmpty = (tpe eq null) || tpe == NoType + + def original: Tree = orig + def setOriginal(tree: Tree): this.type = { + def followOriginal(t: Tree): Tree = t match { + case tt: TypeTree => followOriginal(tt.original) + case t => t + } + + orig = followOriginal(tree); setPos(tree.pos); + this + } + + override def defineType(tp: Type): this.type = { + wasEmpty = isEmpty + setType(tp) + } + } + + def TypeTree(tp: Type): TypeTree = TypeTree() setType tp + + /** Documented definition, eliminated by analyzer */ + case class DocDef(comment: DocComment, definition: Tree) + extends Tree { + override def symbol: Symbol = definition.symbol + override def symbol_=(sym: Symbol) { definition.symbol = sym } + // sean: seems to be important to the IDE + override def isDef = definition.isDef + } + + /** Either an assignment or a named argument. Only appears in argument lists, + * eliminated by typecheck (doTypedApply) + */ + case class AssignOrNamedArg(lhs: Tree, rhs: Tree) + extends TermTree + + case class Parens(args: List[Tree]) extends Tree // only used during parsing + + /** emitted by typer, eliminated by refchecks */ + case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree + // ---- values and creators --------------------------------------- + + /** @param sym the class symbol + * @return the implementation template + */ + def ClassDef(sym: Symbol, impl: Template): ClassDef = + atPos(sym.pos) { + ClassDef(Modifiers(sym.flags), + sym.name.toTypeName, + sym.typeParams map TypeDef, + impl) setSymbol sym + } + + /** Construct class definition with given class symbol, value parameters, + * supercall arguments and template body. + * + * @param sym the class symbol + * @param constrMods the modifiers for the class constructor, i.e. as in `class C private (...)' + * @param vparamss the value parameters -- if they have symbols they + * should be owned by `sym' + * @param argss the supercall arguments + * @param body the template statements without primary constructor + * and value parameter fields. + */ + def ClassDef(sym: Symbol, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree], superPos: Position): ClassDef = + ClassDef(sym, + Template(sym.info.parents map TypeTree, + if (sym.thisSym == sym || phase.erasedTypes) emptyValDef else ValDef(sym.thisSym), + constrMods, vparamss, argss, body, superPos)) + + /** + * @param sym the class symbol + * @param impl the implementation template + */ + def ModuleDef(sym: Symbol, impl: Template): ModuleDef = + atPos(sym.pos) { + ModuleDef(Modifiers(sym.flags), sym.name, impl) setSymbol sym + } + + def ValDef(sym: Symbol, rhs: Tree): ValDef = + atPos(sym.pos) { + ValDef(Modifiers(sym.flags), sym.name, + TypeTree(sym.tpe) setPos focusPos(sym.pos), + rhs) setSymbol sym + } + + def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree) + + object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) { + override def isEmpty = true + super.setPos(NoPosition) + override def setPos(pos: Position) = { assert(false); this } + } + + def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef = + atPos(sym.pos) { + assert(sym != NoSymbol) + DefDef(Modifiers(sym.flags), + sym.name, + sym.typeParams map TypeDef, + vparamss, + TypeTree(sym.tpe.finalResultType) setPos focusPos(sym.pos), + rhs) setSymbol sym + } + + def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef = + DefDef(sym, Modifiers(sym.flags), vparamss, rhs) + + def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef = + DefDef(sym, mods, sym.paramss map (_.map(ValDef)), rhs) + + def DefDef(sym: Symbol, rhs: Tree): DefDef = + DefDef(sym, Modifiers(sym.flags), rhs) + + def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = { + DefDef(sym, rhs(sym.info.paramss)) + } + + /** A TypeDef node which defines given `sym' with given tight hand side `rhs'. */ + def TypeDef(sym: Symbol, rhs: Tree): TypeDef = + atPos(sym.pos) { + TypeDef(Modifiers(sym.flags), sym.name.toTypeName, sym.typeParams map TypeDef, rhs) setSymbol sym + } + + /** A TypeDef node which defines abstract type or type parameter for given `sym' */ + def TypeDef(sym: Symbol): TypeDef = + TypeDef(sym, TypeBoundsTree(TypeTree(sym.info.bounds.lo), TypeTree(sym.info.bounds.hi))) + + def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef = + atPos(sym.pos) { + LabelDef(sym.name, params map Ident, rhs) setSymbol sym + } + + /** Generates a template with constructor corresponding to + * + * constrmods (vparams1_) ... (vparams_n) preSuper { presupers } + * extends superclass(args_1) ... (args_n) with mixins { self => body } + * + * This gets translated to + * + * extends superclass with mixins { self => + * presupers' // presupers without rhs + * vparamss // abstract fields corresponding to value parameters + * def <init>(vparamss) { + * presupers + * super.<init>(args) + * } + * body + * } + */ + def Template(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree], superPos: Position): Template = { + /* Add constructor to template */ + + // create parameters for <init> as synthetic trees. + var vparamss1 = + vparamss map (vps => vps.map { vd => + atPos(focusPos(vd.pos)) { + ValDef( + Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM | BYNAMEPARAM) | PARAM | PARAMACCESSOR) withAnnotations vd.mods.annotations, + vd.name, vd.tpt.duplicate, vd.rhs.duplicate) + }}) + val (edefs, rest) = body span treeInfo.isEarlyDef + val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef + val (lvdefs, gvdefs) = evdefs map { + case vdef @ ValDef(mods, name, tpt, rhs) => + val fld = treeCopy.ValDef( + vdef.duplicate, mods, name, + atPos(focusPos(vdef.pos)) { TypeTree() setOriginal tpt setPos focusPos(tpt.pos) }, // atPos in case + EmptyTree) + val local = treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) + (local, fld) + } unzip + + val constrs = { + if (constrMods hasFlag TRAIT) { + if (body forall treeInfo.isInterfaceMember) List() + else List( + atPos(wrappingPos(superPos, lvdefs)) ( + DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, List(), List(List()), TypeTree(), Block(lvdefs, Literal(()))))) + } else { + // convert (implicit ... ) to ()(implicit ... ) if its the only parameter section + if (vparamss1.isEmpty || !vparamss1.head.isEmpty && vparamss1.head.head.mods.isImplicit) + vparamss1 = List() :: vparamss1; + val superRef: Tree = atPos(superPos) { + Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR) + } + val superCall = (superRef /: argss) (Apply) + List( + atPos(wrappingPos(superPos, lvdefs ::: argss.flatten)) ( + DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(()))))) + } + } + // println("typed template, gvdefs = "+gvdefs+", parents = "+parents+", constrs = "+constrs) + constrs foreach (ensureNonOverlapping(_, parents ::: gvdefs)) + // vparamss2 are used as field definitions for the class. remove defaults + val vparamss2 = vparamss map (vps => vps map { vd => + treeCopy.ValDef(vd, vd.mods &~ DEFAULTPARAM, vd.name, vd.tpt, EmptyTree) + }) + Template(parents, self, gvdefs ::: vparamss2.flatten ::: constrs ::: etdefs ::: rest) + } + + /** casedef shorthand */ + def CaseDef(pat: Tree, body: Tree): CaseDef = CaseDef(pat, EmptyTree, body) + + def Bind(sym: Symbol, body: Tree): Bind = + Bind(sym.name, body) setSymbol sym + + + /** Factory method for object creation `new tpt(args_1)...(args_n)` + * A `New(t, as)` is expanded to: `(new t).<init>(as)` + */ + def New(tpt: Tree, argss: List[List[Tree]]): Tree = { + assert(!argss.isEmpty) + val superRef: Tree = Select(New(tpt), nme.CONSTRUCTOR) + (superRef /: argss) (Apply) + } + + def Apply(sym: Symbol, args: Tree*): Tree = + Apply(Ident(sym), args.toList) + + def Super(sym: Symbol, mix: TypeName): Tree = Super(This(sym), mix) + + def This(sym: Symbol): Tree = This(sym.name.toTypeName) setSymbol sym + + def Select(qualifier: Tree, sym: Symbol): Select = + Select(qualifier, sym.name) setSymbol sym + + def Ident(sym: Symbol): Ident = + Ident(sym.name) setSymbol sym + + /** Block factory that flattens directly nested blocks. + */ + def Block(stats: Tree*): Block = stats match { + case Seq(b @ Block(_, _)) => b + case Seq(stat) => Block(stats.toList, Literal(Constant(()))) + case Seq(_, rest @ _*) => Block(stats.init.toList, stats.last) + } + +// ----- subconstructors -------------------------------------------- + + class ApplyToImplicitArgs(fun: Tree, args: List[Tree]) extends Apply(fun, args) + + class ApplyImplicitView(fun: Tree, args: List[Tree]) extends Apply(fun, args) + +// ------ traversers, copiers, and transformers --------------------------------------------- + + val treeCopy = new LazyTreeCopier() + + class Traverser { + protected var currentOwner: Symbol = definitions.RootClass + def traverse(tree: Tree): Unit = tree match { + case EmptyTree => + ; + case PackageDef(pid, stats) => + traverse(pid) + atOwner(tree.symbol.moduleClass) { + traverseTrees(stats) + } + case ClassDef(mods, name, tparams, impl) => + atOwner(tree.symbol) { + traverseTrees(mods.annotations); traverseTrees(tparams); traverse(impl) + } + case ModuleDef(mods, name, impl) => + atOwner(tree.symbol.moduleClass) { + traverseTrees(mods.annotations); traverse(impl) + } + case ValDef(mods, name, tpt, rhs) => + atOwner(tree.symbol) { + traverseTrees(mods.annotations); traverse(tpt); traverse(rhs) + } + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + atOwner(tree.symbol) { + traverseTrees(mods.annotations); traverseTrees(tparams); traverseTreess(vparamss); traverse(tpt); traverse(rhs) + } + case TypeDef(mods, name, tparams, rhs) => + atOwner(tree.symbol) { + traverseTrees(mods.annotations); traverseTrees(tparams); traverse(rhs) + } + case LabelDef(name, params, rhs) => + traverseTrees(params); traverse(rhs) + case Import(expr, selectors) => + traverse(expr) + case Annotated(annot, arg) => + traverse(annot); traverse(arg) + case Template(parents, self, body) => + traverseTrees(parents) + if (!self.isEmpty) traverse(self) + traverseStats(body, tree.symbol) + case Block(stats, expr) => + traverseTrees(stats); traverse(expr) + case CaseDef(pat, guard, body) => + traverse(pat); traverse(guard); traverse(body) + case Alternative(trees) => + traverseTrees(trees) + case Star(elem) => + traverse(elem) + case Bind(name, body) => + traverse(body) + case UnApply(fun, args) => + traverse(fun); traverseTrees(args) + case ArrayValue(elemtpt, trees) => + traverse(elemtpt); traverseTrees(trees) + case Function(vparams, body) => + atOwner(tree.symbol) { + traverseTrees(vparams); traverse(body) + } + case Assign(lhs, rhs) => + traverse(lhs); traverse(rhs) + case If(cond, thenp, elsep) => + traverse(cond); traverse(thenp); traverse(elsep) + case Match(selector, cases) => + traverse(selector); traverseTrees(cases) + case Return(expr) => + traverse(expr) + case Try(block, catches, finalizer) => + traverse(block); traverseTrees(catches); traverse(finalizer) + case Throw(expr) => + traverse(expr) + case New(tpt) => + traverse(tpt) + case Typed(expr, tpt) => + traverse(expr); traverse(tpt) + case TypeApply(fun, args) => + traverse(fun); traverseTrees(args) + case Apply(fun, args) => + traverse(fun); traverseTrees(args) + case ApplyDynamic(qual, args) => + traverse(qual); traverseTrees(args) + case Super(qual, _) => + traverse(qual) + case This(_) => + ; + case Select(qualifier, selector) => + traverse(qualifier) + case Ident(_) => + ; + case Literal(_) => + ; + case TypeTree() => + ; + case SingletonTypeTree(ref) => + traverse(ref) + case SelectFromTypeTree(qualifier, selector) => + traverse(qualifier) + case CompoundTypeTree(templ) => + traverse(templ) + case AppliedTypeTree(tpt, args) => + traverse(tpt); traverseTrees(args) + case TypeBoundsTree(lo, hi) => + traverse(lo); traverse(hi) + case ExistentialTypeTree(tpt, whereClauses) => + traverse(tpt); traverseTrees(whereClauses) + case SelectFromArray(qualifier, selector, erasure) => + traverse(qualifier) + case AssignOrNamedArg(lhs, rhs) => + traverse(lhs); traverse(rhs) + case DocDef(comment, definition) => + traverse(definition) + case Parens(ts) => + traverseTrees(ts) + case TypeTreeWithDeferredRefCheck() => // TODO: should we traverse the wrapped tree? + // (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check) + } + + def traverseTrees(trees: List[Tree]) { + trees foreach traverse + } + def traverseTreess(treess: List[List[Tree]]) { + treess foreach traverseTrees + } + def traverseStats(stats: List[Tree], exprOwner: Symbol) { + stats foreach (stat => + if (exprOwner != currentOwner) atOwner(exprOwner)(traverse(stat)) + else traverse(stat) + ) + } + + def atOwner(owner: Symbol)(traverse: => Unit) { + val prevOwner = currentOwner + currentOwner = owner + traverse + currentOwner = prevOwner + } + + /** Leave apply available in the generic traverser to do something else. + */ + def apply[T <: Tree](tree: T): T = { traverse(tree); tree } + } + + abstract class TreeCopier { + def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template): ClassDef + def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]): PackageDef + def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template): ModuleDef + def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree): ValDef + def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef + def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree): TypeDef + def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree): LabelDef + def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]): Import + def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef + def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]): Template + def Block(tree: Tree, stats: List[Tree], expr: Tree): Block + def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree): CaseDef + def Alternative(tree: Tree, trees: List[Tree]): Alternative + def Star(tree: Tree, elem: Tree): Star + def Bind(tree: Tree, name: Name, body: Tree): Bind + def UnApply(tree: Tree, fun: Tree, args: List[Tree]): UnApply + def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]): ArrayValue + def Function(tree: Tree, vparams: List[ValDef], body: Tree): Function + def Assign(tree: Tree, lhs: Tree, rhs: Tree): Assign + def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg + def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree): If + def Match(tree: Tree, selector: Tree, cases: List[CaseDef]): Match + def Return(tree: Tree, expr: Tree): Return + def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree): Try + def Throw(tree: Tree, expr: Tree): Throw + def New(tree: Tree, tpt: Tree): New + def Typed(tree: Tree, expr: Tree, tpt: Tree): Typed + def TypeApply(tree: Tree, fun: Tree, args: List[Tree]): TypeApply + def Apply(tree: Tree, fun: Tree, args: List[Tree]): Apply + def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]): ApplyDynamic + def Super(tree: Tree, qual: Tree, mix: TypeName): Super + def This(tree: Tree, qual: Name): This + def Select(tree: Tree, qualifier: Tree, selector: Name): Select + def Ident(tree: Tree, name: Name): Ident + def Literal(tree: Tree, value: Constant): Literal + def TypeTree(tree: Tree): TypeTree + def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck + def Annotated(tree: Tree, annot: Tree, arg: Tree): Annotated + def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree + def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name): SelectFromTypeTree + def CompoundTypeTree(tree: Tree, templ: Template): CompoundTypeTree + def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]): AppliedTypeTree + def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree): TypeBoundsTree + def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]): ExistentialTypeTree + def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray + } + + class StrictTreeCopier extends TreeCopier { + def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template) = + new ClassDef(mods, name.toTypeName, tparams, impl).copyAttrs(tree) + def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]) = + new PackageDef(pid, stats).copyAttrs(tree) + def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template) = + new ModuleDef(mods, name, impl).copyAttrs(tree) + def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) = + new ValDef(mods, name, tpt, rhs).copyAttrs(tree) + def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) = + new DefDef(mods, name, tparams, vparamss, tpt, rhs).copyAttrs(tree) + def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree) = + new TypeDef(mods, name.toTypeName, tparams, rhs).copyAttrs(tree) + def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) = + new LabelDef(name, params, rhs).copyAttrs(tree) + def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]) = + new Import(expr, selectors).copyAttrs(tree) + def DocDef(tree: Tree, comment: DocComment, definition: Tree) = + new DocDef(comment, definition).copyAttrs(tree) + def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]) = + new Template(parents, self, body).copyAttrs(tree) + def Block(tree: Tree, stats: List[Tree], expr: Tree) = + new Block(stats, expr).copyAttrs(tree) + def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) = + new CaseDef(pat, guard, body).copyAttrs(tree) + def Alternative(tree: Tree, trees: List[Tree]) = + new Alternative(trees).copyAttrs(tree) + def Star(tree: Tree, elem: Tree) = + new Star(elem).copyAttrs(tree) + def Bind(tree: Tree, name: Name, body: Tree) = + new Bind(name, body).copyAttrs(tree) + def UnApply(tree: Tree, fun: Tree, args: List[Tree]) = + new UnApply(fun, args).copyAttrs(tree) + def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]) = + new ArrayValue(elemtpt, trees).copyAttrs(tree) + def Function(tree: Tree, vparams: List[ValDef], body: Tree) = + new Function(vparams, body).copyAttrs(tree) + def Assign(tree: Tree, lhs: Tree, rhs: Tree) = + new Assign(lhs, rhs).copyAttrs(tree) + def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = + new AssignOrNamedArg(lhs, rhs).copyAttrs(tree) + def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = + new If(cond, thenp, elsep).copyAttrs(tree) + def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = + new Match(selector, cases).copyAttrs(tree) + def Return(tree: Tree, expr: Tree) = + new Return(expr).copyAttrs(tree) + def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) = + new Try(block, catches, finalizer).copyAttrs(tree) + def Throw(tree: Tree, expr: Tree) = + new Throw(expr).copyAttrs(tree) + def New(tree: Tree, tpt: Tree) = + new New(tpt).copyAttrs(tree) + def Typed(tree: Tree, expr: Tree, tpt: Tree) = + new Typed(expr, tpt).copyAttrs(tree) + def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) = + new TypeApply(fun, args).copyAttrs(tree) + def Apply(tree: Tree, fun: Tree, args: List[Tree]) = + (tree match { + case _: ApplyToImplicitArgs => new ApplyToImplicitArgs(fun, args) + case _: ApplyImplicitView => new ApplyImplicitView(fun, args) + case _ => new Apply(fun, args) + }).copyAttrs(tree) + def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) = + new ApplyDynamic(qual, args).copyAttrs(tree) + def Super(tree: Tree, qual: Tree, mix: TypeName) = + new Super(qual, mix).copyAttrs(tree) + def This(tree: Tree, qual: Name) = + new This(qual.toTypeName).copyAttrs(tree) + def Select(tree: Tree, qualifier: Tree, selector: Name) = + new Select(qualifier, selector).copyAttrs(tree) + def Ident(tree: Tree, name: Name) = + new Ident(name).copyAttrs(tree) + def Literal(tree: Tree, value: Constant) = + new Literal(value).copyAttrs(tree) + def TypeTree(tree: Tree) = + new TypeTree().copyAttrs(tree) + def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { + case dc@TypeTreeWithDeferredRefCheck() => new TypeTreeWithDeferredRefCheck()(dc.check).copyAttrs(tree) + } + def Annotated(tree: Tree, annot: Tree, arg: Tree) = + new Annotated(annot, arg).copyAttrs(tree) + def SingletonTypeTree(tree: Tree, ref: Tree) = + new SingletonTypeTree(ref).copyAttrs(tree) + def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) = + new SelectFromTypeTree(qualifier, selector.toTypeName).copyAttrs(tree) + def CompoundTypeTree(tree: Tree, templ: Template) = + new CompoundTypeTree(templ).copyAttrs(tree) + def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]) = + new AppliedTypeTree(tpt, args).copyAttrs(tree) + def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree) = + new TypeBoundsTree(lo, hi).copyAttrs(tree) + def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]) = + new ExistentialTypeTree(tpt, whereClauses).copyAttrs(tree) + def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = + new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree) + } + + class LazyTreeCopier(treeCopy: TreeCopier) extends TreeCopier { + def this() = this(new StrictTreeCopier) + def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template) = tree match { + case t @ ClassDef(mods0, name0, tparams0, impl0) + if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && (impl0 == impl) => t + case _ => treeCopy.ClassDef(tree, mods, name, tparams, impl) + } + def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]) = tree match { + case t @ PackageDef(pid0, stats0) + if (pid0 == pid) && (stats0 == stats) => t + case _ => treeCopy.PackageDef(tree, pid, stats) + } + def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template) = tree match { + case t @ ModuleDef(mods0, name0, impl0) + if (mods0 == mods) && (name0 == name) && (impl0 == impl) => t + case _ => treeCopy.ModuleDef(tree, mods, name, impl) + } + def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) = tree match { + case t @ ValDef(mods0, name0, tpt0, rhs0) + if (mods0 == mods) && (name0 == name) && (tpt0 == tpt) && (rhs0 == rhs) => t + case _ => treeCopy.ValDef(tree, mods, name, tpt, rhs) + } + def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) = tree match { + case t @ DefDef(mods0, name0, tparams0, vparamss0, tpt0, rhs0) + if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && + (vparamss0 == vparamss) && (tpt0 == tpt) && (rhs == rhs0) => t + case _ => treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs) + } + def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree) = tree match { + case t @ TypeDef(mods0, name0, tparams0, rhs0) + if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && (rhs0 == rhs) => t + case _ => treeCopy.TypeDef(tree, mods, name, tparams, rhs) + } + def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) = tree match { + case t @ LabelDef(name0, params0, rhs0) + if (name0 == name) && (params0 == params) && (rhs0 == rhs) => t + case _ => treeCopy.LabelDef(tree, name, params, rhs) + } + def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]) = tree match { + case t @ Import(expr0, selectors0) + if (expr0 == expr) && (selectors0 == selectors) => t + case _ => treeCopy.Import(tree, expr, selectors) + } + def DocDef(tree: Tree, comment: DocComment, definition: Tree) = tree match { + case t @ DocDef(comment0, definition0) + if (comment0 == comment) && (definition0 == definition) => t + case _ => treeCopy.DocDef(tree, comment, definition) + } + def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]) = tree match { + case t @ Template(parents0, self0, body0) + if (parents0 == parents) && (self0 == self) && (body0 == body) => t + case _ => treeCopy.Template(tree, parents, self, body) + } + def Block(tree: Tree, stats: List[Tree], expr: Tree) = tree match { + case t @ Block(stats0, expr0) + if ((stats0 == stats) && (expr0 == expr)) => t + case _ => treeCopy.Block(tree, stats, expr) + } + def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) = tree match { + case t @ CaseDef(pat0, guard0, body0) + if (pat0 == pat) && (guard0 == guard) && (body0 == body) => t + case _ => treeCopy.CaseDef(tree, pat, guard, body) + } + def Alternative(tree: Tree, trees: List[Tree]) = tree match { + case t @ Alternative(trees0) + if trees0 == trees => t + case _ => treeCopy.Alternative(tree, trees) + } + def Star(tree: Tree, elem: Tree) = tree match { + case t @ Star(elem0) + if elem0 == elem => t + case _ => treeCopy.Star(tree, elem) + } + def Bind(tree: Tree, name: Name, body: Tree) = tree match { + case t @ Bind(name0, body0) + if (name0 == name) && (body0 == body) => t + case _ => treeCopy.Bind(tree, name, body) + } + def UnApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { + case t @ UnApply(fun0, args0) + if (fun0 == fun) && (args0 == args) => t + case _ => treeCopy.UnApply(tree, fun, args) + } + def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]) = tree match { + case t @ ArrayValue(elemtpt0, trees0) + if (elemtpt0 == elemtpt) && (trees0 == trees) => t + case _ => treeCopy.ArrayValue(tree, elemtpt, trees) + } + def Function(tree: Tree, vparams: List[ValDef], body: Tree) = tree match { + case t @ Function(vparams0, body0) + if (vparams0 == vparams) && (body0 == body) => t + case _ => treeCopy.Function(tree, vparams, body) + } + def Assign(tree: Tree, lhs: Tree, rhs: Tree) = tree match { + case t @ Assign(lhs0, rhs0) + if (lhs0 == lhs) && (rhs0 == rhs) => t + case _ => treeCopy.Assign(tree, lhs, rhs) + } + def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = tree match { + case t @ AssignOrNamedArg(lhs0, rhs0) + if (lhs0 == lhs) && (rhs0 == rhs) => t + case _ => treeCopy.AssignOrNamedArg(tree, lhs, rhs) + } + def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = tree match { + case t @ If(cond0, thenp0, elsep0) + if (cond0 == cond) && (thenp0 == thenp) && (elsep0 == elsep) => t + case _ => treeCopy.If(tree, cond, thenp, elsep) + } + def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = tree match { + case t @ Match(selector0, cases0) + if (selector0 == selector) && (cases0 == cases) => t + case _ => treeCopy.Match(tree, selector, cases) + } + def Return(tree: Tree, expr: Tree) = tree match { + case t @ Return(expr0) + if expr0 == expr => t + case _ => treeCopy.Return(tree, expr) + } + def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) = tree match { + case t @ Try(block0, catches0, finalizer0) + if (block0 == block) && (catches0 == catches) && (finalizer0 == finalizer) => t + case _ => treeCopy.Try(tree, block, catches, finalizer) + } + def Throw(tree: Tree, expr: Tree) = tree match { + case t @ Throw(expr0) + if expr0 == expr => t + case _ => treeCopy.Throw(tree, expr) + } + def New(tree: Tree, tpt: Tree) = tree match { + case t @ New(tpt0) + if tpt0 == tpt => t + case _ => treeCopy.New(tree, tpt) + } + def Typed(tree: Tree, expr: Tree, tpt: Tree) = tree match { + case t @ Typed(expr0, tpt0) + if (expr0 == expr) && (tpt0 == tpt) => t + case _ => treeCopy.Typed(tree, expr, tpt) + } + def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { + case t @ TypeApply(fun0, args0) + if (fun0 == fun) && (args0 == args) => t + case _ => treeCopy.TypeApply(tree, fun, args) + } + def Apply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { + case t @ Apply(fun0, args0) + if (fun0 == fun) && (args0 == args) => t + case _ => treeCopy.Apply(tree, fun, args) + } + def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) = tree match { + case t @ ApplyDynamic(qual0, args0) + if (qual0 == qual) && (args0 == args) => t + case _ => treeCopy.ApplyDynamic(tree, qual, args) + } + def Super(tree: Tree, qual: Tree, mix: TypeName) = tree match { + case t @ Super(qual0, mix0) + if (qual0 == qual) && (mix0 == mix) => t + case _ => treeCopy.Super(tree, qual, mix) + } + def This(tree: Tree, qual: Name) = tree match { + case t @ This(qual0) + if qual0 == qual => t + case _ => treeCopy.This(tree, qual) + } + def Select(tree: Tree, qualifier: Tree, selector: Name) = tree match { + case t @ Select(qualifier0, selector0) + if (qualifier0 == qualifier) && (selector0 == selector) => t + case _ => treeCopy.Select(tree, qualifier, selector) + } + def Ident(tree: Tree, name: Name) = tree match { + case t @ Ident(name0) + if name0 == name => t + case _ => treeCopy.Ident(tree, name) + } + def Literal(tree: Tree, value: Constant) = tree match { + case t @ Literal(value0) + if value0 == value => t + case _ => treeCopy.Literal(tree, value) + } + def TypeTree(tree: Tree) = tree match { + case t @ TypeTree() => t + case _ => treeCopy.TypeTree(tree) + } + def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { + case t @ TypeTreeWithDeferredRefCheck() => t + case _ => treeCopy.TypeTreeWithDeferredRefCheck(tree) + } + def Annotated(tree: Tree, annot: Tree, arg: Tree) = tree match { + case t @ Annotated(annot0, arg0) + if (annot0==annot) => t + case _ => treeCopy.Annotated(tree, annot, arg) + } + def SingletonTypeTree(tree: Tree, ref: Tree) = tree match { + case t @ SingletonTypeTree(ref0) + if ref0 == ref => t + case _ => treeCopy.SingletonTypeTree(tree, ref) + } + def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) = tree match { + case t @ SelectFromTypeTree(qualifier0, selector0) + if (qualifier0 == qualifier) && (selector0 == selector) => t + case _ => treeCopy.SelectFromTypeTree(tree, qualifier, selector) + } + def CompoundTypeTree(tree: Tree, templ: Template) = tree match { + case t @ CompoundTypeTree(templ0) + if templ0 == templ => t + case _ => treeCopy.CompoundTypeTree(tree, templ) + } + def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]) = tree match { + case t @ AppliedTypeTree(tpt0, args0) + if (tpt0 == tpt) && (args0 == args) => t + case _ => treeCopy.AppliedTypeTree(tree, tpt, args) + } + def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree) = tree match { + case t @ TypeBoundsTree(lo0, hi0) + if (lo0 == lo) && (hi0 == hi) => t + case _ => treeCopy.TypeBoundsTree(tree, lo, hi) + } + def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]) = tree match { + case t @ ExistentialTypeTree(tpt0, whereClauses0) + if (tpt0 == tpt) && (whereClauses0 == whereClauses) => t + case _ => treeCopy.ExistentialTypeTree(tree, tpt, whereClauses) + } + def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = tree match { + case t @ SelectFromArray(qualifier0, selector0, _) + if (qualifier0 == qualifier) && (selector0 == selector) => t + case _ => treeCopy.SelectFromArray(tree, qualifier, selector, erasure) + } + } + + abstract class Transformer { + val treeCopy: TreeCopier = new LazyTreeCopier + protected var currentOwner: Symbol = definitions.RootClass + protected def currentMethod = currentOwner.enclMethod + protected def currentClass = currentOwner.enclClass + protected def currentPackage = currentOwner.toplevelClass.owner + def transform(tree: Tree): Tree = tree match { + case EmptyTree => + tree + case PackageDef(pid, stats) => + treeCopy.PackageDef( + tree, transform(pid).asInstanceOf[RefTree], + atOwner(tree.symbol.moduleClass) { + transformStats(stats, currentOwner) + } + ) + case ClassDef(mods, name, tparams, impl) => + atOwner(tree.symbol) { + treeCopy.ClassDef(tree, transformModifiers(mods), name, + transformTypeDefs(tparams), transformTemplate(impl)) + } + case ModuleDef(mods, name, impl) => + atOwner(tree.symbol.moduleClass) { + treeCopy.ModuleDef(tree, transformModifiers(mods), + name, transformTemplate(impl)) + } + case ValDef(mods, name, tpt, rhs) => + atOwner(tree.symbol) { + treeCopy.ValDef(tree, transformModifiers(mods), + name, transform(tpt), transform(rhs)) + } + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + atOwner(tree.symbol) { + treeCopy.DefDef(tree, transformModifiers(mods), name, + transformTypeDefs(tparams), transformValDefss(vparamss), + transform(tpt), transform(rhs)) + } + case TypeDef(mods, name, tparams, rhs) => + atOwner(tree.symbol) { + treeCopy.TypeDef(tree, transformModifiers(mods), name, + transformTypeDefs(tparams), transform(rhs)) + } + case LabelDef(name, params, rhs) => + treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy' + case Import(expr, selectors) => + treeCopy.Import(tree, transform(expr), selectors) + case DocDef(comment, definition) => + treeCopy.DocDef(tree, comment, transform(definition)) + case Template(parents, self, body) => + treeCopy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol)) + case Block(stats, expr) => + treeCopy.Block(tree, transformStats(stats, currentOwner), transform(expr)) + case CaseDef(pat, guard, body) => + treeCopy.CaseDef(tree, transform(pat), transform(guard), transform(body)) + case Alternative(trees) => + treeCopy.Alternative(tree, transformTrees(trees)) + case Star(elem) => + treeCopy.Star(tree, transform(elem)) + case Bind(name, body) => + treeCopy.Bind(tree, name, transform(body)) + case UnApply(fun, args) => + treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala + case ArrayValue(elemtpt, trees) => + treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees)) + case Function(vparams, body) => + atOwner(tree.symbol) { + treeCopy.Function(tree, transformValDefs(vparams), transform(body)) + } + case Assign(lhs, rhs) => + treeCopy.Assign(tree, transform(lhs), transform(rhs)) + case AssignOrNamedArg(lhs, rhs) => + treeCopy.AssignOrNamedArg(tree, transform(lhs), transform(rhs)) + case If(cond, thenp, elsep) => + treeCopy.If(tree, transform(cond), transform(thenp), transform(elsep)) + case Match(selector, cases) => + treeCopy.Match(tree, transform(selector), transformCaseDefs(cases)) + case Return(expr) => + treeCopy.Return(tree, transform(expr)) + case Try(block, catches, finalizer) => + treeCopy.Try(tree, transform(block), transformCaseDefs(catches), transform(finalizer)) + case Throw(expr) => + treeCopy.Throw(tree, transform(expr)) + case New(tpt) => + treeCopy.New(tree, transform(tpt)) + case Typed(expr, tpt) => + treeCopy.Typed(tree, transform(expr), transform(tpt)) + case TypeApply(fun, args) => + treeCopy.TypeApply(tree, transform(fun), transformTrees(args)) + case Apply(fun, args) => + treeCopy.Apply(tree, transform(fun), transformTrees(args)) + case ApplyDynamic(qual, args) => + treeCopy.ApplyDynamic(tree, transform(qual), transformTrees(args)) + case Super(qual, mix) => + treeCopy.Super(tree, transform(qual), mix) + case This(qual) => + treeCopy.This(tree, qual) + case Select(qualifier, selector) => + treeCopy.Select(tree, transform(qualifier), selector) + case Ident(name) => + treeCopy.Ident(tree, name) + case Literal(value) => + treeCopy.Literal(tree, value) + case TypeTree() => + treeCopy.TypeTree(tree) + case TypeTreeWithDeferredRefCheck() => + treeCopy.TypeTreeWithDeferredRefCheck(tree) + case Annotated(annot, arg) => + treeCopy.Annotated(tree, transform(annot), transform(arg)) + case SingletonTypeTree(ref) => + treeCopy.SingletonTypeTree(tree, transform(ref)) + case SelectFromTypeTree(qualifier, selector) => + treeCopy.SelectFromTypeTree(tree, transform(qualifier), selector) + case CompoundTypeTree(templ) => + treeCopy.CompoundTypeTree(tree, transformTemplate(templ)) + case AppliedTypeTree(tpt, args) => + treeCopy.AppliedTypeTree(tree, transform(tpt), transformTrees(args)) + case TypeBoundsTree(lo, hi) => + treeCopy.TypeBoundsTree(tree, transform(lo), transform(hi)) + case ExistentialTypeTree(tpt, whereClauses) => + treeCopy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses)) + case SelectFromArray(qualifier, selector, erasure) => + treeCopy.SelectFromArray(tree, transform(qualifier), selector, erasure) + } + + def transformTrees(trees: List[Tree]): List[Tree] = + trees mapConserve (transform(_)) + def transformTemplate(tree: Template): Template = + transform(tree: Tree).asInstanceOf[Template] + def transformTypeDefs(trees: List[TypeDef]): List[TypeDef] = + trees mapConserve (tree => transform(tree).asInstanceOf[TypeDef]) + def transformValDef(tree: ValDef): ValDef = + if (tree.isEmpty) tree else transform(tree).asInstanceOf[ValDef] + def transformValDefs(trees: List[ValDef]): List[ValDef] = + trees mapConserve (transformValDef(_)) + def transformValDefss(treess: List[List[ValDef]]): List[List[ValDef]] = + treess mapConserve (transformValDefs(_)) + def transformCaseDefs(trees: List[CaseDef]): List[CaseDef] = + trees mapConserve (tree => transform(tree).asInstanceOf[CaseDef]) + def transformIdents(trees: List[Ident]): List[Ident] = + trees mapConserve (tree => transform(tree).asInstanceOf[Ident]) + def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = + stats mapConserve (stat => + if (exprOwner != currentOwner && stat.isTerm) atOwner(exprOwner)(transform(stat)) + else transform(stat)) filter (EmptyTree !=) + def transformModifiers(mods: Modifiers): Modifiers = + Modifiers(mods.flags, mods.privateWithin, transformTrees(mods.annotations), mods.positions) + + def atOwner[A](owner: Symbol)(trans: => A): A = { + val prevOwner = currentOwner + currentOwner = owner + val result = trans + currentOwner = prevOwner + result + } + } + + private[scala] def duplicateTree(tree: Tree): Tree = duplicator transform tree + + private lazy val duplicator = new Transformer { + override val treeCopy = new StrictTreeCopier + override def transform(t: Tree) = { + val t1 = super.transform(t) + if ((t1 ne t) && isRangePos(t1.pos)) t1 setPos focusPos(t.pos) + t1 + } + } + + private class ShallowDuplicator(orig: Tree) extends Transformer { + override val treeCopy = new StrictTreeCopier + override def transform(tree: Tree) = + if (tree eq orig) super.transform(tree) + else tree + } + + class TreeSubstituter(from: List[Symbol], to: List[Tree]) extends Transformer { + override def transform(tree: Tree): Tree = tree match { + case Ident(_) => + def subst(from: List[Symbol], to: List[Tree]): Tree = + if (from.isEmpty) tree + else if (tree.symbol == from.head) to.head + else subst(from.tail, to.tail); + subst(from, to) + case _ => + super.transform(tree) + } + } + + class TreeTypeSubstituter(val from: List[Symbol], val to: List[Type]) extends Traverser { + val typeSubst = new SubstTypeMap(from, to) + def fromContains = typeSubst.fromContains + + override def traverse(tree: Tree) { + if (tree.tpe ne null) tree.tpe = typeSubst(tree.tpe) + if (tree.isDef) { + val sym = tree.symbol + val info1 = typeSubst(sym.info) + if (info1 ne sym.info) sym.setInfo(info1) + } + super.traverse(tree) + } + override def apply[T <: Tree](tree: T): T = super.apply(tree.duplicate) + override def toString() = "TreeTypeSubstituter("+from+","+to+")" + } + + lazy val EmptyTreeTypeSubstituter = new TreeTypeSubstituter(List(), List()) + + class TreeSymSubstTraverser(val from: List[Symbol], val to: List[Symbol]) extends Traverser { + val subst = new SubstSymMap(from, to) + override def traverse(tree: Tree) { + if (tree.tpe ne null) tree.tpe = subst(tree.tpe) + if (tree.isDef) { + val sym = tree.symbol + val info1 = subst(sym.info) + if (info1 ne sym.info) sym.setInfo(info1) + } + super.traverse(tree) + } + override def apply[T <: Tree](tree: T): T = super.apply(tree.duplicate) + override def toString() = "TreeSymSubstTraverser("+from+","+to+")" + } + + /** Substitute symbols in 'from' with symbols in 'to'. Returns a new + * tree using the new symbols and whose Ident and Select nodes are + * name-consistent with the new symbols. + */ + class TreeSymSubstituter(from: List[Symbol], to: List[Symbol]) extends Transformer { + val symSubst = new SubstSymMap(from, to) + override def transform(tree: Tree): Tree = { + def subst(from: List[Symbol], to: List[Symbol]) { + if (!from.isEmpty) + if (tree.symbol == from.head) tree setSymbol to.head + else subst(from.tail, to.tail) + } + + if (tree.tpe ne null) tree.tpe = symSubst(tree.tpe) + if (tree.hasSymbol) { + subst(from, to) + tree match { + case Ident(name0) if tree.symbol != NoSymbol => + treeCopy.Ident(tree, tree.symbol.name) + case Select(qual, name0) => + treeCopy.Select(tree, transform(qual), tree.symbol.name) + case _ => + super.transform(tree) + } + } else + super.transform(tree) + } + def apply[T <: Tree](tree: T): T = transform(tree).asInstanceOf[T] + override def toString() = "TreeSymSubstituter("+from+","+to+")" + } + + class ChangeOwnerTraverser(val oldowner: Symbol, val newowner: Symbol) extends Traverser { + def changeOwner(tree: Tree) = { + if ((tree.isDef || tree.isInstanceOf[Function]) && + tree.symbol != NoSymbol && tree.symbol.owner == oldowner) + tree.symbol.owner = newowner + } + override def traverse(tree: Tree) { + changeOwner(tree) + super.traverse(tree) + } + } + + object posAssigner extends Traverser { + var pos: Position = _ + override def traverse(t: Tree) { + if (t != EmptyTree && t.pos == NoPosition) { + t.setPos(pos) + super.traverse(t) + } + } + } + + def atPos[T <: Tree](pos: Position)(tree: T): T = { + posAssigner.pos = pos + posAssigner.traverse(tree) + tree + } + + class ForeachPartialTreeTraverser(pf: PartialFunction[Tree, Tree]) extends Traverser { + override def traverse(tree: Tree) { + val t = if (pf isDefinedAt tree) pf(tree) else tree + super.traverse(t) + } + } + + class ForeachTreeTraverser(f: Tree => Unit) extends Traverser { + override def traverse(t: Tree) { + f(t) + super.traverse(t) + } + } + + class FilterTreeTraverser(p: Tree => Boolean) extends Traverser { + val hits = new ListBuffer[Tree] + override def traverse(t: Tree) { + if (p(t)) hits += t + super.traverse(t) + } + } + + class FindTreeTraverser(p: Tree => Boolean) extends Traverser { + var result: Option[Tree] = None + override def traverse(t: Tree) { + if (result.isEmpty) { + if (p(t)) result = Some(t) + super.traverse(t) + } + } + } + + object resetPos extends Traverser { + override def traverse(t: Tree) { + if (t != EmptyTree) t.setPos(NoPosition) + super.traverse(t) + } + } + + + /** resets symbol and tpe fields in a tree, @see ResetAttrsTraverse + */ + def resetAllAttrs[A<:Tree](x:A): A = { new ResetAttrsTraverser().traverse(x); x } + def resetLocalAttrs[A<:Tree](x:A): A = { new ResetLocalAttrsTraverser().traverse(x); x } + + /** A traverser which resets symbol and tpe fields of all nodes in a given tree + * except for (1) TypeTree nodes, whose <code>.tpe</code> field is kept, and + * (2) This(pkg) nodes, where pkg refers to a package symbol -- their attributes are kept, and + * (3) if a <code>.symbol</code> field refers to a symbol which is defined + * outside the tree, it is also kept. + * + * (2) is necessary because some This(pkg) are generated where pkg is not + * an enclosing package.n In that case, resetting the symbol would cause the + * next type checking run to fail. See #3152. + * + * (bq:) This traverser has mutable state and should be discarded after use + */ + private class ResetAttrsTraverser extends Traverser { + protected def isLocal(sym: Symbol): Boolean = true + protected def resetDef(tree: Tree) { + tree.symbol = NoSymbol + } + override def traverse(tree: Tree): Unit = { + tree match { + case _: DefTree | Function(_, _) | Template(_, _, _) => + resetDef(tree) + tree.tpe = null + case tpt: TypeTree => + if (tpt.wasEmpty) tree.tpe = null + case This(_) if tree.symbol != null && tree.symbol.isPackageClass => + ; + case EmptyTree => + ; + case _ => + if (tree.hasSymbol && isLocal(tree.symbol)) tree.symbol = NoSymbol + tree.tpe = null + } + super.traverse(tree) + } + } + + private class ResetLocalAttrsTraverser extends ResetAttrsTraverser { + private val erasedSyms = HashSet[Symbol](8) + override protected def isLocal(sym: Symbol) = erasedSyms(sym) + override protected def resetDef(tree: Tree) { + erasedSyms addEntry tree.symbol + super.resetDef(tree) + } + override def traverse(tree: Tree): Unit = tree match { + case Template(parents, self, body) => + for (stat <- body) + if (stat.isDef) erasedSyms.addEntry(stat.symbol) + super.traverse(tree) + case _ => + super.traverse(tree) + } + } + + /* A standard pattern match + case EmptyTree => + case PackageDef(pid, stats) => + // package pid { stats } + case ClassDef(mods, name, tparams, impl) => + // mods class name [tparams] impl where impl = extends parents { defs } + case ModuleDef(mods, name, impl) => (eliminated by refcheck) + // mods object name impl where impl = extends parents { defs } + case ValDef(mods, name, tpt, rhs) => + // mods val name: tpt = rhs + // note missing type information is expressed by tpt = TypeTree() + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + // mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs + // note missing type information is expressed by tpt = TypeTree() + case TypeDef(mods, name, tparams, rhs) => (eliminated by erasure) + // mods type name[tparams] = rhs + // mods type name[tparams] >: lo <: hi, where lo, hi are in a TypeBoundsTree, + and DEFERRED is set in mods + case LabelDef(name, params, rhs) => + // used for tailcalls and like + // while/do are desugared to label defs as follows: + // while (cond) body ==> LabelDef($L, List(), if (cond) { body; L$() } else ()) + // do body while (cond) ==> LabelDef($L, List(), body; if (cond) L$() else ()) + case Import(expr, selectors) => (eliminated by typecheck) + // import expr.{selectors} + // Selectors are a list of pairs of names (from, to). + // The last (and maybe only name) may be a nme.WILDCARD + // for instance + // import qual.{x, y => z, _} would be represented as + // Import(qual, List(("x", "x"), ("y", "z"), (WILDCARD, null))) + case Template(parents, self, body) => + // extends parents { self => body } + // if self is missing it is represented as emptyValDef + case Block(stats, expr) => + // { stats; expr } + case CaseDef(pat, guard, body) => (eliminated by transmatch/explicitouter) + // case pat if guard => body + case Alternative(trees) => (eliminated by transmatch/explicitouter) + // pat1 | ... | patn + case Star(elem) => (eliminated by transmatch/explicitouter) + // pat* + case Bind(name, body) => (eliminated by transmatch/explicitouter) + // name @ pat + case UnApply(fun: Tree, args) (introduced by typer, eliminated by transmatch/explicitouter) + // used for unapply's + case ArrayValue(elemtpt, trees) => (introduced by uncurry) + // used to pass arguments to vararg arguments + // for instance, printf("%s%d", foo, 42) is translated to after uncurry to: + // Apply( + // Ident("printf"), + // Literal("%s%d"), + // ArrayValue(<Any>, List(Ident("foo"), Literal(42)))) + case Function(vparams, body) => (eliminated by lambdaLift) + // vparams => body where vparams:List[ValDef] + case Assign(lhs, rhs) => + // lhs = rhs + case If(cond, thenp, elsep) => + // if (cond) thenp else elsep + case Match(selector, cases) => + // selector match { cases } + case Return(expr) => + // return expr + case Try(block, catches, finalizer) => + // try block catch { catches } finally finalizer where catches: List[CaseDef] + case Throw(expr) => + // throw expr + case New(tpt) => + // new tpt always in the context: (new tpt).<init>[targs](args) + case Typed(expr, tpt) => (eliminated by erasure) + // expr: tpt + case TypeApply(fun, args) => + // fun[args] + case Apply(fun, args) => + // fun(args) + // for instance fun[targs](args) is expressed as Apply(TypeApply(fun, targs), args) + case ApplyDynamic(qual, args) (introduced by erasure, eliminated by cleanup) + // fun(args) + case Super(qual, mix) => + // qual.super[mix] if qual and/or mix is empty, ther are tpnme.EMPTY + case This(qual) => + // qual.this + case Select(qualifier, selector) => + // qualifier.selector + case Ident(name) => + // name + // note: type checker converts idents that refer to enclosing fields or methods + // to selects; name ==> this.name + case Literal(value) => + // value + case TypeTree() => (introduced by refcheck) + // a type that's not written out, but given in the tpe attribute + case Annotated(annot, arg) => (eliminated by typer) + // arg @annot for types, arg: @annot for exprs + case SingletonTypeTree(ref) => (eliminated by uncurry) + // ref.type + case SelectFromTypeTree(qualifier, selector) => (eliminated by uncurry) + // qualifier # selector, a path-dependent type p.T is expressed as p.type # T + case CompoundTypeTree(templ: Template) => (eliminated by uncurry) + // parent1 with ... with parentN { refinement } + case AppliedTypeTree(tpt, args) => (eliminated by uncurry) + // tpt[args] + case TypeBoundsTree(lo, hi) => (eliminated by uncurry) + // >: lo <: hi + case ExistentialTypeTree(tpt, whereClauses) => (eliminated by uncurry) + // tpt forSome { whereClauses } + +*/ +} + diff --git a/src/compiler/scala/reflect/common/TypeDebugging.scala b/src/compiler/scala/reflect/common/TypeDebugging.scala new file mode 100644 index 0000000000..6028473b39 --- /dev/null +++ b/src/compiler/scala/reflect/common/TypeDebugging.scala @@ -0,0 +1,72 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.reflect +package common + +trait TypeDebugging { + self: SymbolTable => + + import definitions._ + + // @M toString that is safe during debugging (does not normalize, ...) + object TypeDebugStrings { + object str { + def parentheses(xs: List[_]): String = xs.mkString("(", ", ", ")") + def brackets(xs: List[_]): String = if (xs.isEmpty) "" else xs.mkString("[", ", ", "]") + def tparams(tparams: List[Type]): String = brackets(tparams map debug) + def parents(ps: List[Type]): String = (ps map debug).mkString(" with ") + def refine(defs: Scope): String = defs.toList.mkString("{", " ;\n ", "}") + } + + def dump(tp: Type): Unit = { + println("** " + tp + " / " + tp.getClass + " **") + import tp._ + + println("typeSymbol = " + typeSymbol) + println("termSymbol = " + termSymbol) + println("widen = " + widen) + println("deconst = " + deconst) + println("typeOfThis = " + typeOfThis) + println("bounds = " + bounds) + println("parents = " + parents) + println("prefixChain = " + prefixChain) + println("typeConstructor = " + typeConstructor) + println(" .. typeConstructor.typeParams = " + typeConstructor.typeParams) + println(" .. _.variance = " + (typeConstructor.typeParams map (_.variance))) + println("typeArgs = " + typeArgs) + println("resultType = " + resultType) + println("finalResultType = " + finalResultType) + println("paramss = " + paramss) + println("paramTypes = " + paramTypes) + println("typeParams = " + typeParams) + println("boundSyms = " + boundSyms) + println("baseTypeSeq = " + baseTypeSeq) + println("baseClasses = " + baseClasses) + println("toLongString = " + toLongString) + } + + private def debug(tp: Type): String = tp match { + case TypeRef(pre, sym, args) => debug(pre) + "." + sym.nameString + str.tparams(args) + case ThisType(sym) => sym.nameString + ".this" + case SingleType(pre, sym) => debug(pre) +"."+ sym.nameString +".type" + case RefinedType(parents, defs) => str.parents(parents) + str.refine(defs) + case ClassInfoType(parents, defs, clazz) => "class "+ clazz.nameString + str.parents(parents) + str.refine(defs) + case PolyType(tparams, result) => str.brackets(tparams) + " " + debug(result) + case TypeBounds(lo, hi) => ">: "+ debug(lo) +" <: "+ debug(hi) + case tv @ TypeVar(_, _) => tv.toString + case ExistentialType(tparams, qtpe) => "forSome "+ str.brackets(tparams) + " " + debug(qtpe) + case _ => tp.toString + } + def debugString(tp: Type) = debug(tp) + } + private def TDS = TypeDebugStrings + + def paramString(tp: Type) = TDS.str parentheses (tp.params map (_.defString)) + def typeParamsString(tp: Type) = TDS.str brackets (tp.typeParams map (_.defString)) + def typeArgsString(tp: Type) = TDS.str brackets (tp.typeArgs map (_.safeToString)) + def debugString(tp: Type) = TDS debugString tp +} + diff --git a/src/compiler/scala/reflect/common/Types.scala b/src/compiler/scala/reflect/common/Types.scala new file mode 100644 index 0000000000..78407cd868 --- /dev/null +++ b/src/compiler/scala/reflect/common/Types.scala @@ -0,0 +1,5699 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common + +import scala.collection.{ mutable, immutable } +import scala.ref.WeakReference +import mutable.ListBuffer +//import ast.TreeGen +//import util.{ Position, NoPosition } +import Flags._ +import scala.util.control.ControlThrowable +import scala.annotation.tailrec +import util.Statistics._ + +/* 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 + + /** 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[scala] 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[scala] 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 { + + /** 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 + + /** 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 + + /** 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 completed (i.e. not a lazy type)? + */ + def isComplete: Boolean = true + + /** If this is a lazy type, assign a new type to `sym'. */ + def complete(sym: Symbol) {} + + /** 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' forSome { type T' <: T with Singleton } + * Overridden where we know more about where types come from. + */ + def narrow: Type = + if (phase.erasedTypes) this + else commonOwner(this) freshExistential ".type" setInfo singletonBounds(this) tpe + + /** 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 + + + /** 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 = + 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)) + } + } + + + + /** 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) + "#" + + /** Convert toString avoiding infinite recursions by cutting off + * after `maxTostringRecursions` recursion levels. Uses `safeToString` + * to produce a string on each level. + */ + override def toString: String = + if (tostringRecursions >= maxTostringRecursions) + "..." + else + try { + tostringRecursions += 1 + safeToString + } finally { + tostringRecursions -= 1 + } + + /** Method to be implemented in subclasses. + * Converts this type to a string in calling toString for its parts. + */ + def safeToString: String = super.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 = { + val suspension = TypeVar.Suspension + // 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 + this foreach { + case tv: TypeVar => suspension suspend tv + case _ => () + } + } + + 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) + suspension.resumeAll + 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) + while ((prevEntry ne null) && + !(prevEntry.sym == sym || + prevEntry.sym.owner != sym.owner && + !sym.hasFlag(PRIVATE) && { + if (self eq null) self = this.narrow + self.memberType(prevEntry.sym) matches self.memberType(sym) + })) { + 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) + suspension.resumeAll + 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" + } + + object ThisType { + def apply(sym: Symbol): Type = + if (!phase.erasedTypes) unique(new ThisType(sym) with UniqueType) + else if (sym.isImplClass) sym.typeOfThis + else sym.tpe + } + + /** A class for singleton types of the form <prefix>.<sym.name>.type. + * Cannot be created directly; one should always use + * `singleType' for creation. + */ + 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" + } + + 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" + } + + object SuperType { + def apply(thistp: Type, supertp: Type): Type = + if (phase.erasedTypes) supertp + else unique(new SuperType(thistp, supertp) with UniqueType) + } + + /** 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" + } + + object TypeBounds { + 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 TypeBounds(lo, hi) with UniqueType) + } + + /** 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 <parents_n> { decls }' + * Cannot be created directly; + * one should always use `refinedType' for creation. + */ + case class RefinedType(override val parents: List[Type], + override val decls: Scope) extends CompoundType { + + override def isHigherKinded = ( + parents.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" + } + + object RefinedType { + def apply(parents: List[Type], decls: Scope, clazz: Symbol) = + new RefinedType(parents, decls) { override def typeSymbol = 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</pre> + * @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</pre>, for + * all elements <pre>sym</pre> 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" + } + + 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" + } + + object ConstantType { + def apply(value: Constant): ConstantType = { + class UniqueConstantType 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 + } + unique(new UniqueConstantType) + } + } + + private var volatileRecursions: Int = 0 + private val pendingVolatiles = new mutable.HashSet[Symbol] + + /** A class for named types of the form + * `<prefix>.<sym.name>[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 val parentsCache = new ListOfTypesCache { + @inline final def calculate() = thisInfo.parents map transform + } + private var baseTypeSeqCache: BaseTypeSeq = _ + private var baseTypeSeqPeriod = NoPeriod + + 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 = + if (sym.isAliasType) normalize + else if (sym.isNonClassType) transformInfo(sym.info) + else sym.info + + def relativeInfo = if (sym.isNonClassType) transformInfo(pre.memberInfo(sym)) else pre.memberInfo(sym) + + 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] = parentsCache.get() + 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 + + // @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 = typeParamsDirect map (_.typeConstructor) //@M must be .typeConstructor + + // (!result.isEmpty) IFF isHigherKinded + override def typeParams: List[Symbol] = if (isHigherKinded) typeParamsDirect else List() + + override def typeConstructor = TypeRef(pre, sym, Nil) + // note: does not go through typeRef. There's no need to because neither `pre' nor `sym' changes. + // And there's a performance advantage to call TypeRef directly. + + + // a reference (in a Scala program) to a type that has type parameters, but where the reference does not include type arguments + // note that it doesn't matter whether the symbol refers to a java or scala symbol, + // it does matter whether it occurs in java or scala code + // typerefs w/o type params that occur in java signatures/code are considered raw types, and are represented as existential types + 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)) + typeRef(pre, sym, actuals) + else if (sameLength(formals, actuals)) // partial application (needed in infer when bunching type arguments from classes and methods together) + typeRef(pre, sym, dummyArgs).subst(formals, actuals) + else ErrorType + } + else + super.instantiateTypeParams(formals, actuals) + + + private var normalized: Type = null + + @inline private def betaReduce: Type = { + assert(sameLength(sym.info.typeParams, typeArgs), this) + // isHKSubType0 introduces synthetic type params so that betaReduce can first apply sym.info to typeArgs before calling asSeenFrom + // asSeenFrom then skips synthetic type params, which are used to reduce HO subtyping to first-order subtyping, but which can't be instantiated from the given prefix and class + // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) // this crashes pos/depmet_implicit_tpbetareduce.scala + transform(sym.info.resultType) + } + + // @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, typeRef(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 + + 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)) + return normalize.typeArgs.init.mkString("(", ", ", ")") + " => " + normalize.typeArgs.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" + } + + object TypeRef { + def apply(pre: Type, sym: Symbol, args: List[Type]): Type = { + unique(new TypeRef(pre, sym, args) with UniqueType) + } + } + + /** 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" + } + + 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" + } + + /** 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" + } + + 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)) + } + } + } + + /** 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()) + def apply(tparam: Symbol) = new TypeVar(tparam.tpeHK, new TypeConstraint, List(), tparam.typeParams) // TODO why not initialise TypeConstraint with bounds of tparam? + 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[TypeVar] 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) && { + unifySimple || unifyFull(tp) || unifyFull(tp.dealias) || unifyFull(tp.widen) || 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</code>; + * 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" + } + + /** 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 { + override def isComplete: Boolean = false + override def complete(sym: Symbol) + override def safeToString = "<?>" + 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) + // why not do the hash-consing in the SingleType.apply() + // factory, like the other UniqueTypes? + unique(new SingleType(pre1, sym1) with UniqueType) + } + } + + /** 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) + } + } + } + + /** 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), _) => typeRef(pre, sym, Nil) //@M drop type args to Any/Nothing + case TypeRef(pre, sym, _) => typeRef(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 typeRef(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]() + 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(_, _) => // stop to avoid infinite expansions + tp + 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? + gen.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 = from.toSet // avoiding repeatedly traversing from + 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 + + 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) + + 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 { + 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) => typeRef(pre, sym, args) + case SingleType(pre, _) => singleType(pre, sym) + } + override def apply(tp: Type): Type = if (from.isEmpty) tp else { + 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(typeRef(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) { + gen.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 typeRef(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+" <:<? "+tp2 + } + +// Helper Methods ------------------------------------------------------------- + + final val LubGlbMargin = 0 + + /** The maximum allowable depth of lubs or glbs over types `ts' + * This is the maximum depth of all types in the base type sequences + * of each of the types `ts', plus LubGlbMargin + */ + def lubDepth(ts: List[Type]) = { + var d = 0 + for (tp <- ts) d = math.max(d, tp.baseTypeSeqDepth) + d + LubGlbMargin + } + + /** Is intersection of given types populated? That is, + * for all types tp1, tp2 in intersection + * for all common base classes bc of tp1 and tp2 + * let bt1, bt2 be the base types of tp1, tp2 relative to class bc + * Then: + * bt1 and bt2 have the same prefix, and + * any corresponding non-variant type arguments of bt1 and bt2 are the same + */ + def isPopulated(tp1: Type, tp2: Type): Boolean = { + def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { + case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => + assert(sym1 == sym2) + pre1 =:= pre2 && + ((args1, args2, sym1.typeParams).zipped forall { + (arg1, arg2, tparam) => + //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG + if (tparam.variance == 0) arg1 =:= arg2 + else if (arg1.isInstanceOf[TypeVar]) + // if left-hand argument is a typevar, make it compatible with variance + // this is for more precise pattern matching + // todo: work this in the spec of this method + // also: think what happens if there are embedded typevars? + if (tparam.variance < 0) arg1 <:< arg2 else arg2 <:< arg1 + else true + }) + case (et: ExistentialType, _) => + et.withTypeVars(isConsistent(_, tp2)) + case (_, et: ExistentialType) => + et.withTypeVars(isConsistent(tp1, _)) + } + + def check(tp1: Type, tp2: Type) = + if (tp1.typeSymbol.isClass && tp1.typeSymbol.hasFlag(FINAL)) + tp1 <:< tp2 || isNumericValueClass(tp1.typeSymbol) && isNumericValueClass(tp2.typeSymbol) + else tp1.baseClasses forall (bc => + tp2.baseTypeIndex(bc) < 0 || isConsistent(tp1.baseType(bc), tp2.baseType(bc))) + + check(tp1, tp2)/* && check(tp2, tp1)*/ // need to investgate why this can't be made symmetric -- neg/gadts1 fails, and run/existials also. + } + + /** Does a pattern of type `patType' need an outer test when executed against + * selector type `selType' in context defined by `currentOwner'? + */ + def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = { + def createDummyClone(pre: Type): Type = { + val dummy = currentOwner.enclClass.newValue(NoPosition, nme.ANYNAME).setInfo(pre.widen) + singleType(ThisType(currentOwner.enclClass), dummy) + } + def maybeCreateDummyClone(pre: Type, sym: Symbol): Type = pre match { + case SingleType(pre1, sym1) => + if (sym1.isModule && sym1.isStatic) { + NoType + } else if (sym1.isModule && sym.owner == sym1.moduleClass) { + val pre2 = maybeCreateDummyClone(pre1, sym1) + if (pre2 eq NoType) pre2 + else singleType(pre2, sym1) + } else { + createDummyClone(pre) + } + case ThisType(clazz) => + if (clazz.isModuleClass) + maybeCreateDummyClone(clazz.typeOfThis, sym) + else if (sym.owner == clazz && (sym.hasFlag(PRIVATE) || sym.privateWithin == clazz)) + NoType + else + createDummyClone(pre) + case _ => + NoType + } + patType match { + case TypeRef(pre, sym, args) => + val pre1 = maybeCreateDummyClone(pre, sym) + (pre1 ne NoType) && isPopulated(typeRef(pre1, sym, args), selType) + case _ => + false + } + } + + private var subsametypeRecursions: Int = 0 + + private def isUnifiable(pre1: Type, pre2: Type) = + (beginsWithTypeVarOrIsRefined(pre1) || beginsWithTypeVarOrIsRefined(pre2)) && (pre1 =:= pre2) + + /** Returns true iff we are past phase specialize, + * sym1 and sym2 are two existential skolems with equal names and bounds, + * and pre1 and pre2 are equal prefixes + */ + private def isSameSpecializedSkolem(sym1: Symbol, sym2: Symbol, pre1: Type, pre2: Type) = { + sym1.isExistentialSkolem && sym2.isExistentialSkolem && + sym1.name == sym2.name && + phase.specialized && + sym1.info =:= sym2.info && + pre1 =:= pre2 + } + + private def equalSymsAndPrefixes(sym1: Symbol, pre1: Type, sym2: Symbol, pre2: Type): Boolean = + if (sym1 == sym2) sym1.hasPackageFlag || phase.erasedTypes || pre1 =:= pre2 + else (sym1.name == sym2.name) && isUnifiable(pre1, pre2) + + /** Do `tp1' and `tp2' denote equivalent types? + */ + def isSameType(tp1: Type, tp2: Type): Boolean = try { + incCounter(sametypeCount) + subsametypeRecursions += 1 + undoLog undoUnless { + isSameType1(tp1, tp2) + } + } finally { + subsametypeRecursions -= 1 + // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866) + // it doesn't help to keep separate recursion counts for the three methods that now share it + // if (subsametypeRecursions == 0) undoLog.clear() + } + + def isDifferentType(tp1: Type, tp2: Type): Boolean = try { + subsametypeRecursions += 1 + undoLog undo { // undo type constraints that arise from operations in this block + !isSameType1(tp1, tp2) + } + } finally { + subsametypeRecursions -= 1 + // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866) + // it doesn't help to keep separate recursion counts for the three methods that now share it + // if (subsametypeRecursions == 0) undoLog.clear() + } + + def isDifferentTypeConstructor(tp1: Type, tp2: Type): Boolean = tp1 match { + case TypeRef(pre1, sym1, _) => + tp2 match { + case TypeRef(pre2, sym2, _) => sym1 != sym2 || isDifferentType(pre1, pre2) + case _ => true + } + case _ => true + } + + def normalizePlus(tp: Type) = + if (isRawType(tp)) rawToExistential(tp) + else tp.normalize + + /* + todo: change to: + def normalizePlus(tp: Type) = tp match { + case TypeRef(pre, sym, List()) => + if (!sym.isInitialized) sym.rawInfo.load(sym) + if (sym.isJavaDefined && !sym.typeParams.isEmpty) rawToExistential(tp) + else tp.normalize + case _ => tp.normalize + } + */ +/* + private def isSameType0(tp1: Type, tp2: Type): Boolean = { + if (tp1 eq tp2) return true + ((tp1, tp2) match { + case (ErrorType, _) => true + case (WildcardType, _) => true + case (_, ErrorType) => true + case (_, WildcardType) => true + + case (NoType, _) => false + case (NoPrefix, _) => tp2.typeSymbol.isPackageClass + case (_, NoType) => false + case (_, NoPrefix) => tp1.typeSymbol.isPackageClass + + case (ThisType(sym1), ThisType(sym2)) + if (sym1 == sym2) => + true + case (SingleType(pre1, sym1), SingleType(pre2, sym2)) + if (equalSymsAndPrefixes(sym1, pre1, sym2, pre2)) => + true +/* + case (SingleType(pre1, sym1), ThisType(sym2)) + if (sym1.isModule && + sym1.moduleClass == sym2 && + pre1 =:= sym2.owner.thisType) => + true + case (ThisType(sym1), SingleType(pre2, sym2)) + if (sym2.isModule && + sym2.moduleClass == sym1 && + pre2 =:= sym1.owner.thisType) => + true +*/ + case (ConstantType(value1), ConstantType(value2)) => + value1 == value2 + case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => + equalSymsAndPrefixes(sym1, pre1, sym2, pre2) && + ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) || + isSameTypes(args1, args2)) + // @M! normalize reduces higher-kinded case to PolyType's + case (RefinedType(parents1, ref1), RefinedType(parents2, ref2)) => + def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall { + sym2 => + var e1 = s1.lookupEntry(sym2.name) + (e1 ne null) && { + val substSym = sym2.info.substThis(sym2.owner, e1.sym.owner.thisType) + var isEqual = false + while (!isEqual && (e1 ne null)) { + isEqual = e1.sym.info =:= substSym + e1 = s1.lookupNextEntry(e1) + } + isEqual + } + } + //Console.println("is same? " + tp1 + " " + tp2 + " " + tp1.typeSymbol.owner + " " + tp2.typeSymbol.owner)//DEBUG + isSameTypes(parents1, parents2) && isSubScope(ref1, ref2) && isSubScope(ref2, ref1) + case (MethodType(params1, res1), MethodType(params2, res2)) => + // new dependent types: probably fix this, use substSym as done for PolyType + (isSameTypes(tp1.paramTypes, tp2.paramTypes) && + res1 =:= res2 && + tp1.isImplicit == tp2.isImplicit) + case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => + // assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length))) + (tparams1.length == tparams2.length) && (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && // @M looks like it might suffer from same problem as #2210 + res1 =:= res2.substSym(tparams2, tparams1) + case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) => + (tparams1.length == tparams2.length) && (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && // @M looks like it might suffer from same problem as #2210 + res1 =:= res2.substSym(tparams2, tparams1) + case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => + lo1 =:= lo2 && hi1 =:= hi2 + case (BoundedWildcardType(bounds), _) => + bounds containsType tp2 + case (_, BoundedWildcardType(bounds)) => + bounds containsType tp1 + case (tv @ TypeVar(_,_), tp) => + tv.registerTypeEquality(tp, true) + case (tp, tv @ TypeVar(_,_)) => + tv.registerTypeEquality(tp, false) + case (AnnotatedType(_,_,_), _) => + annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations + case (_, AnnotatedType(_,_,_)) => + annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations + case (_: SingletonType, _: SingletonType) => + var origin1 = tp1 + while (origin1.underlying.isInstanceOf[SingletonType]) { + assert(origin1 ne origin1.underlying, origin1) + origin1 = origin1.underlying + } + var origin2 = tp2 + while (origin2.underlying.isInstanceOf[SingletonType]) { + assert(origin2 ne origin2.underlying, origin2) + origin2 = origin2.underlying + } + ((origin1 ne tp1) || (origin2 ne tp2)) && (origin1 =:= origin2) + case _ => + false + }) || { + val tp1n = normalizePlus(tp1) + val tp2n = normalizePlus(tp2) + ((tp1n ne tp1) || (tp2n ne tp2)) && isSameType(tp1n, tp2n) + } + } +*/ + private def isSameType1(tp1: Type, tp2: Type): Boolean = { + if ((tp1 eq tp2) || + (tp1 eq ErrorType) || (tp1 eq WildcardType) || + (tp2 eq ErrorType) || (tp2 eq WildcardType)) + true + else if ((tp1 eq NoType) || (tp2 eq NoType)) + false + else if (tp1 eq NoPrefix) + tp2.typeSymbol.isPackageClass + else if (tp2 eq NoPrefix) + tp1.typeSymbol.isPackageClass + else { + isSameType2(tp1, tp2) || { + val tp1n = normalizePlus(tp1) + val tp2n = normalizePlus(tp2) + ((tp1n ne tp1) || (tp2n ne tp2)) && isSameType(tp1n, tp2n) + } + } + } + + def isSameType2(tp1: Type, tp2: Type): Boolean = { + tp1 match { + case tr1: TypeRef => + tp2 match { + case tr2: TypeRef => + return (equalSymsAndPrefixes(tr1.sym, tr1.pre, tr2.sym, tr2.pre) && + ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) || + isSameTypes(tr1.args, tr2.args))) || + ((tr1.pre, tr2.pre) match { + case (tv @ TypeVar(_,_), _) => tv.registerTypeSelection(tr1.sym, tr2) + case (_, tv @ TypeVar(_,_)) => tv.registerTypeSelection(tr2.sym, tr1) + case _ => false + }) + case _ => + } + case tt1: ThisType => + tp2 match { + case tt2: ThisType => + if (tt1.sym == tt2.sym) return true + case _ => + } + case st1: SingleType => + tp2 match { + case st2: SingleType => + if (equalSymsAndPrefixes(st1.sym, st1.pre, st2.sym, st2.pre)) return true + case _ => + } + case ct1: ConstantType => + tp2 match { + case ct2: ConstantType => + return (ct1.value == ct2.value) + case _ => + } + case rt1: RefinedType => + tp2 match { + case rt2: RefinedType => // + def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall { + sym2 => + var e1 = s1.lookupEntry(sym2.name) + (e1 ne null) && { + val substSym = sym2.info.substThis(sym2.owner, e1.sym.owner.thisType) + var isEqual = false + while (!isEqual && (e1 ne null)) { + isEqual = e1.sym.info =:= substSym + e1 = s1.lookupNextEntry(e1) + } + isEqual + } + } + //Console.println("is same? " + tp1 + " " + tp2 + " " + tp1.typeSymbol.owner + " " + tp2.typeSymbol.owner)//DEBUG + return isSameTypes(rt1.parents, rt2.parents) && { + val decls1 = rt1.decls + val decls2 = rt2.decls + isSubScope(decls1, decls2) && isSubScope(decls2, decls1) + } + case _ => + } + case mt1: MethodType => + tp2 match { + case mt2: MethodType => + // DEPMETTODO new dependent types: probably fix this, use substSym as done for PolyType + return isSameTypes(mt1.paramTypes, mt2.paramTypes) && + mt1.resultType =:= mt2.resultType && + mt1.isImplicit == mt2.isImplicit + // note: no case NullaryMethodType(restpe) => return mt1.params.isEmpty && mt1.resultType =:= restpe + case _ => + } + case NullaryMethodType(restpe1) => + tp2 match { + // note: no case mt2: MethodType => return mt2.params.isEmpty && restpe =:= mt2.resultType + case NullaryMethodType(restpe2) => + return restpe1 =:= restpe2 + case _ => + } + case PolyType(tparams1, res1) => + tp2 match { + case PolyType(tparams2, res2) => +// assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length))) + // @M looks like it might suffer from same problem as #2210 + return ( + (sameLength(tparams1, tparams2)) && // corresponds does not check length of two sequences before checking the predicate + (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && + res1 =:= res2.substSym(tparams2, tparams1) + ) + case _ => + } + case ExistentialType(tparams1, res1) => + tp2 match { + case ExistentialType(tparams2, res2) => + // @M looks like it might suffer from same problem as #2210 + return ( + // corresponds does not check length of two sequences before checking the predicate -- faster & needed to avoid crasher in #2956 + sameLength(tparams1, tparams2) && + (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && + res1 =:= res2.substSym(tparams2, tparams1) + ) + case _ => + } + case TypeBounds(lo1, hi1) => + tp2 match { + case TypeBounds(lo2, hi2) => + return lo1 =:= lo2 && hi1 =:= hi2 + case _ => + } + case BoundedWildcardType(bounds) => + return bounds containsType tp2 + case _ => + } + tp2 match { + case BoundedWildcardType(bounds) => + return bounds containsType tp1 + case _ => + } + tp1 match { + case tv @ TypeVar(_,_) => + return tv.registerTypeEquality(tp2, true) + case _ => + } + tp2 match { + case tv @ TypeVar(_,_) => + return tv.registerTypeEquality(tp1, false) + case _ => + } + tp1 match { + case _: AnnotatedType => + return annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations + case _ => + } + tp2 match { + case _: AnnotatedType => + return annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations + case _ => + } + tp1 match { + case _: SingletonType => + tp2 match { + case _: SingletonType => + @inline def chaseDealiasedUnderlying(tp: Type): Type = { + var origin = tp + var next = origin.underlying.dealias + while (next.isInstanceOf[SingletonType]) { + assert(origin ne next, origin) + origin = next + next = origin.underlying.dealias + } + origin + } + val origin1 = chaseDealiasedUnderlying(tp1) + val origin2 = chaseDealiasedUnderlying(tp2) + ((origin1 ne tp1) || (origin2 ne tp2)) && (origin1 =:= origin2) + case _ => + false + } + case _ => + false + } + } + + /** Are `tps1' and `tps2' lists of pairwise equivalent + * types? + */ + def isSameTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1 corresponds tps2)(_ =:= _) + + /** True if two lists have the same length. Since calling length on linear sequences + * is O(n), it is an inadvisable way to test length equality. + */ + final def sameLength(xs1: List[_], xs2: List[_]) = compareLengths(xs1, xs2) == 0 + @tailrec final def compareLengths(xs1: List[_], xs2: List[_]): Int = + if (xs1.isEmpty) { if (xs2.isEmpty) 0 else -1 } + else if (xs2.isEmpty) 1 + else compareLengths(xs1.tail, xs2.tail) + + /** Again avoiding calling length, but the lengthCompare interface is clunky. + */ + final def hasLength(xs: List[_], len: Int) = xs.lengthCompare(len) == 0 + + private val pendingSubTypes = new mutable.HashSet[SubTypePair] + private var basetypeRecursions: Int = 0 + private val pendingBaseTypes = new mutable.HashSet[Type] + + def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, AnyDepth) + + def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean = try { + subsametypeRecursions += 1 + + undoLog undoUnless { // if subtype test fails, it should not affect constraints on typevars + if (subsametypeRecursions >= LogPendingSubTypesThreshold) { + val p = new SubTypePair(tp1, tp2) + if (pendingSubTypes(p)) + false + else + try { + pendingSubTypes += p + isSubType2(tp1, tp2, depth) + } finally { + pendingSubTypes -= p + } + } else { + isSubType2(tp1, tp2, depth) + } + } + } finally { + subsametypeRecursions -= 1 + // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866) + // it doesn't help to keep separate recursion counts for the three methods that now share it + // if (subsametypeRecursions == 0) undoLog.clear() + } + + /** Does this type have a prefix that begins with a type variable, + * or is it a refinement type? For type prefixes that fulfil this condition, + * type selections with the same name of equal (wrt) =:= prefixes are + * considered equal wrt =:= + */ + def beginsWithTypeVarOrIsRefined(tp: Type): Boolean = tp match { + case SingleType(pre, sym) => + !(sym hasFlag PACKAGE) && beginsWithTypeVarOrIsRefined(pre) + case tv@TypeVar(_, constr) => + !tv.instValid || beginsWithTypeVarOrIsRefined(constr.inst) + case RefinedType(_, _) => + true + case _ => + false + } + + def instTypeVar(tp: Type): Type = tp match { + case TypeRef(pre, sym, args) => + typeRef(instTypeVar(pre), sym, args) + case SingleType(pre, sym) => + singleType(instTypeVar(pre), sym) + case TypeVar(_, constr) => + instTypeVar(constr.inst) + case _ => + tp + } + + def isErrorOrWildcard(tp: Type) = (tp eq ErrorType) || (tp eq WildcardType) + + def isSingleType(tp: Type) = tp match { + case ThisType(_) | SuperType(_, _) | SingleType(_, _) => true + case _ => false + } + + def isConstantType(tp: Type) = tp match { + case ConstantType(_) => true + case _ => false + } + + // @assume tp1.isHigherKinded || tp2.isHigherKinded + def isHKSubType0(tp1: Type, tp2: Type, depth: Int): Boolean = ( + tp1.typeSymbol == NothingClass + || + tp2.typeSymbol == AnyClass // @M Any and Nothing are super-type resp. subtype of every well-kinded type + || // @M! normalize reduces higher-kinded case to PolyType's + ((tp1.normalize.withoutAnnotations , tp2.normalize.withoutAnnotations) match { + case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => // @assume tp1.isHigherKinded && tp2.isHigherKinded (as they were both normalized to PolyType) + sameLength(tparams1, tparams2) && { + if (tparams1.head.owner.isMethod) { // fast-path: polymorphic method type -- type params cannot be captured + (tparams1 corresponds tparams2)((p1, p2) => p2.info.substSym(tparams2, tparams1) <:< p1.info) && + res1 <:< res2.substSym(tparams2, tparams1) + } else { // normalized higher-kinded type + //@M for an example of why we need to generate fresh symbols, see neg/tcpoly_ticket2101.scala + val tpsFresh = cloneSymbols(tparams1) + + (tparams1 corresponds tparams2)((p1, p2) => + p2.info.substSym(tparams2, tpsFresh) <:< p1.info.substSym(tparams1, tpsFresh)) && + res1.substSym(tparams1, tpsFresh) <:< res2.substSym(tparams2, tpsFresh) + + //@M the forall in the previous test could be optimised to the following, + // but not worth the extra complexity since it only shaves 1s from quick.comp + // (List.forall2(tpsFresh/*optimisation*/, tparams2)((p1, p2) => + // p2.info.substSym(tparams2, tpsFresh) <:< p1.info /*optimisation, == (p1 from tparams1).info.substSym(tparams1, tpsFresh)*/) && + // this optimisation holds because inlining cloneSymbols in `val tpsFresh = cloneSymbols(tparams1)` gives: + // val tpsFresh = tparams1 map (_.cloneSymbol) + // for (tpFresh <- tpsFresh) tpFresh.setInfo(tpFresh.info.substSym(tparams1, tpsFresh)) + } + } && annotationsConform(tp1.normalize, tp2.normalize) + case (_, _) => false // @assume !tp1.isHigherKinded || !tp2.isHigherKinded + // --> thus, cannot be subtypes (Any/Nothing has already been checked) + })) + + /** True if all three arguments have the same number of elements and + * the function is true for all the triples. + */ + @tailrec final def corresponds3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C], f: (A, B, C) => Boolean): Boolean = { + if (xs1.isEmpty) xs2.isEmpty && xs3.isEmpty + else !xs2.isEmpty && !xs3.isEmpty && f(xs1.head, xs2.head, xs3.head) && corresponds3(xs1.tail, xs2.tail, xs3.tail, f) + } + + def isSubArg(t1: Type, t2: Type, variance: Int) = + (variance > 0 || t2 <:< t1) && (variance < 0 || t1 <:< t2) + + def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean = + corresponds3(tps1, tps2, tparams map (_.variance), isSubArg) + + def differentOrNone(tp1: Type, tp2: Type) = if (tp1 eq tp2) NoType else tp1 + + /** Does type `tp1' conform to `tp2'? + */ + private def isSubType2(tp1: Type, tp2: Type, depth: Int): Boolean = { + if ((tp1 eq tp2) || isErrorOrWildcard(tp1) || isErrorOrWildcard(tp2)) return true + if ((tp1 eq NoType) || (tp2 eq NoType)) return false + if (tp1 eq NoPrefix) return (tp2 eq NoPrefix) || tp2.typeSymbol.isPackageClass + if (tp2 eq NoPrefix) return tp1.typeSymbol.isPackageClass + if (isSingleType(tp1) && isSingleType(tp2) || isConstantType(tp1) && isConstantType(tp2)) return tp1 =:= tp2 + if (tp1.isHigherKinded || tp2.isHigherKinded) return isHKSubType0(tp1, tp2, depth) + + /** First try, on the right: + * - unwrap Annotated types, BoundedWildcardTypes, + * - bind TypeVars on the right, if lhs is not Annotated nor BoundedWildcard + * - handle common cases for first-kind TypeRefs on both sides as a fast path. + */ + def firstTry = tp2 match { + // fast path: two typerefs, none of them HK + case tr2: TypeRef => + tp1 match { + case tr1: TypeRef => + val sym1 = tr1.sym + val sym2 = tr2.sym + val pre1 = tr1.pre + val pre2 = tr2.pre + (((if (sym1 == sym2) phase.erasedTypes || pre1 <:< pre2 + else (sym1.name == sym2.name && !sym1.isModuleClass && !sym2.isModuleClass && + (isUnifiable(pre1, pre2) || isSameSpecializedSkolem(sym1, sym2, pre1, pre2)))) && + isSubArgs(tr1.args, tr2.args, sym1.typeParams)) + || + sym2.isClass && { + val base = tr1 baseType sym2 + (base ne tr1) && base <:< tr2 + } + || + thirdTryRef(tr1, tr2)) + case _ => + secondTry + } + case AnnotatedType(_, _, _) => + tp1.withoutAnnotations <:< tp2.withoutAnnotations && annotationsConform(tp1, tp2) + case BoundedWildcardType(bounds) => + tp1 <:< bounds.hi + case tv2 @ TypeVar(_, constr2) => + tp1 match { + case AnnotatedType(_, _, _) | BoundedWildcardType(_) => + secondTry + case _ => + tv2.registerBound(tp1, true) + } + case _ => + secondTry + } + + /** Second try, on the left: + * - unwrap AnnotatedTypes, BoundedWildcardTypes, + * - bind typevars, + * - handle existential types by skolemization. + */ + def secondTry = tp1 match { + case AnnotatedType(_, _, _) => + tp1.withoutAnnotations <:< tp2.withoutAnnotations && annotationsConform(tp1, tp2) + case BoundedWildcardType(bounds) => + tp1.bounds.lo <:< tp2 + case tv @ TypeVar(_,_) => + tv.registerBound(tp2, false) + case ExistentialType(_, _) => + try { + skolemizationLevel += 1 + tp1.skolemizeExistential <:< tp2 + } finally { + skolemizationLevel -= 1 + } + case _ => + thirdTry + } + + def thirdTryRef(tp1: Type, tp2: TypeRef): Boolean = { + val sym2 = tp2.sym + sym2 match { + case NotNullClass => tp1.isNotNull + case SingletonClass => tp1.isStable || fourthTry + case _: ClassSymbol => + if (isRaw(sym2, tp2.args)) + isSubType(tp1, rawToExistential(tp2), depth) + else if (sym2.name == tpnme.REFINE_CLASS_NAME) + isSubType(tp1, sym2.info, depth) + else + fourthTry + case _: TypeSymbol => + if (sym2 hasFlag DEFERRED) { + val tp2a = tp2.bounds.lo + isDifferentTypeConstructor(tp2, tp2a) && tp1 <:< tp2a || fourthTry + } else { + isSubType(tp1.normalize, tp2.normalize, depth) + } + case _ => + fourthTry + } + } + + /** Third try, on the right: + * - decompose refined types. + * - handle typerefs, existentials, and notnull types. + * - handle left+right method types, polytypes, typebounds + */ + def thirdTry = tp2 match { + case tr2: TypeRef => + thirdTryRef(tp1, tr2) + case rt2: RefinedType => + (rt2.parents forall (tp1 <:< _)) && + (rt2.decls.toList forall tp1.specializes) + case et2: ExistentialType => + et2.withTypeVars(tp1 <:< _, depth) || fourthTry + case nn2: NotNullType => + tp1.isNotNull && tp1 <:< nn2.underlying + case mt2: MethodType => + tp1 match { + case mt1 @ MethodType(params1, res1) => + val params2 = mt2.params + val res2 = mt2.resultType + (sameLength(params1, params2) && + matchingParams(params1, params2, mt1.isJava, mt2.isJava) && + (res1 <:< res2) && + mt1.isImplicit == mt2.isImplicit) + // TODO: if mt1.params.isEmpty, consider NullaryMethodType? + case _ => + false + } + case pt2 @ NullaryMethodType(_) => + tp1 match { + // TODO: consider MethodType mt for which mt.params.isEmpty?? + case pt1 @ NullaryMethodType(_) => + pt1.resultType <:< pt2.resultType + case _ => + false + } + case TypeBounds(lo2, hi2) => + tp1 match { + case TypeBounds(lo1, hi1) => + lo2 <:< lo1 && hi1 <:< hi2 + case _ => + false + } + case _ => + fourthTry + } + + /** Fourth try, on the left: + * - handle typerefs, refined types, notnull and singleton types. + */ + def fourthTry = tp1 match { + case tr1 @ TypeRef(_, sym1, _) => + sym1 match { + case NothingClass => true + case NullClass => + tp2 match { + case TypeRef(_, sym2, _) => + sym2.isClass && (sym2 isNonBottomSubClass ObjectClass) && + !(tp2.normalize.typeSymbol isNonBottomSubClass NotNullClass) + case _ => + isSingleType(tp2) && tp1 <:< tp2.widen + } + case _: ClassSymbol => + if (isRaw(sym1, tr1.args)) + isSubType(rawToExistential(tp1), tp2, depth) + else + sym1.name == tpnme.REFINE_CLASS_NAME && + isSubType(sym1.info, tp2, depth) + case _: TypeSymbol => + if (sym1 hasFlag DEFERRED) { + val tp1a = tp1.bounds.hi + isDifferentTypeConstructor(tp1, tp1a) && tp1a <:< tp2 + } else { + isSubType(tp1.normalize, tp2.normalize, depth) + } + case _ => + false + } + case RefinedType(parents1, _) => + parents1 exists (_ <:< tp2) + case _: SingletonType | _: NotNullType => + tp1.underlying <:< tp2 + case _ => + false + } + + firstTry + } + + /** Are `tps1' and `tps2' lists of equal length such + * that all elements of `tps1' conform to corresponding elements + * of `tps2'? + */ + def isSubTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1 corresponds tps2)(_ <:< _) + + /** Does type `tp' implement symbol `sym' with same or + * stronger type? Exact only if `sym' is a member of some + * refinement type, otherwise we might return false negatives. + */ + def specializesSym(tp: Type, sym: Symbol): Boolean = + tp.typeSymbol == NothingClass || + tp.typeSymbol == NullClass && (sym.owner isSubClass ObjectClass) || + (tp.nonPrivateMember(sym.name).alternatives exists + (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym))) + + /** Does member `sym1' of `tp1' have a stronger type + * than member `sym2' of `tp2'? + */ + private def specializesSym(tp1: Type, sym1: Symbol, tp2: Type, sym2: Symbol): Boolean = { + val info1 = tp1.memberInfo(sym1) + val info2 = tp2.memberInfo(sym2).substThis(tp2.typeSymbol, tp1) + //System.out.println("specializes "+tp1+"."+sym1+":"+info1+sym1.locationString+" AND "+tp2+"."+sym2+":"+info2)//DEBUG + sym2.isTerm && (info1 <:< info2) /*&& (!sym2.isStable || sym1.isStable) */ || + sym2.isAbstractType && { + val memberTp1 = tp1.memberType(sym1) + // println("kinds conform? "+(memberTp1, tp1, sym2, kindsConform(List(sym2), List(memberTp1), tp2, sym2.owner))) + info2.bounds.containsType(memberTp1) && + kindsConform(List(sym2), List(memberTp1), tp1, sym1.owner) + } || + sym2.isAliasType && tp2.memberType(sym2).substThis(tp2.typeSymbol, tp1) =:= tp1.memberType(sym1) //@MAT ok + } + + /** A function implementing `tp1' matches `tp2' */ + final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = { + def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean = ( + sameLength(tparams1, tparams2) && + matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple) + ) + def lastTry = + tp2 match { + case ExistentialType(_, res2) if alwaysMatchSimple => + matchesType(tp1, res2, true) + case MethodType(_, _) => + false + case PolyType(tparams2, res2) => + tparams2.isEmpty && matchesType(tp1, res2, alwaysMatchSimple) + case _ => + alwaysMatchSimple || tp1 =:= tp2 + } + tp1 match { + case mt1 @ MethodType(params1, res1) => + tp2 match { + case mt2 @ MethodType(params2, res2) => + sameLength(params1, params2) && // useful pre-screening optimization + matchingParams(params1, params2, mt1.isJava, mt2.isJava) && + matchesType(res1, res2, alwaysMatchSimple) && + mt1.isImplicit == mt2.isImplicit + case NullaryMethodType(res2) => + if (params1.isEmpty) matchesType(res1, res2, alwaysMatchSimple) + else matchesType(tp1, res2, alwaysMatchSimple) + case ExistentialType(_, res2) => + alwaysMatchSimple && matchesType(tp1, res2, true) + case _ => + false + } + case mt1 @ NullaryMethodType(res1) => + tp2 match { + case mt2 @ MethodType(Nil, res2) => // could never match if params nonEmpty, and !mt2.isImplicit is implied by empty param list + matchesType(res1, res2, alwaysMatchSimple) + case NullaryMethodType(res2) => + matchesType(res1, res2, alwaysMatchSimple) + case ExistentialType(_, res2) => + alwaysMatchSimple && matchesType(tp1, res2, true) + case _ => + matchesType(res1, tp2, alwaysMatchSimple) + } + case PolyType(tparams1, res1) => + tp2 match { + case PolyType(tparams2, res2) => + matchesQuantified(tparams1, tparams2, res1, res2) + case ExistentialType(_, res2) => + alwaysMatchSimple && matchesType(tp1, res2, true) + case _ => + false // remember that tparams1.nonEmpty is now an invariant of PolyType + } + case ExistentialType(tparams1, res1) => + tp2 match { + case ExistentialType(tparams2, res2) => + matchesQuantified(tparams1, tparams2, res1, res2) + case _ => + if (alwaysMatchSimple) matchesType(res1, tp2, true) + else lastTry + } + case _ => + lastTry + } + } + +/** matchesType above is an optimized version of the following implementation: + + def matchesType2(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = { + def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean = + tparams1.length == tparams2.length && + matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple) + (tp1, tp2) match { + case (MethodType(params1, res1), MethodType(params2, res2)) => + params1.length == params2.length && // useful pre-secreening optimization + matchingParams(params1, params2, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && + matchesType(res1, res2, alwaysMatchSimple) && + tp1.isImplicit == tp2.isImplicit + case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => + matchesQuantified(tparams1, tparams2, res1, res2) + case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) => + matchesType(rtp1, rtp2, alwaysMatchSimple) + case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) => + matchesType(rtp1, rtp2, alwaysMatchSimple) + case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) => + matchesQuantified(tparams1, tparams2, res1, res2) + case (ExistentialType(_, res1), _) if alwaysMatchSimple => + matchesType(res1, tp2, alwaysMatchSimple) + case (_, ExistentialType(_, res2)) if alwaysMatchSimple => + matchesType(tp1, res2, alwaysMatchSimple) + case (NullaryMethodType(rtp1), _) => + matchesType(rtp1, tp2, alwaysMatchSimple) + case (_, NullaryMethodType(rtp2)) => + matchesType(tp1, rtp2, alwaysMatchSimple) + case (MethodType(_, _), _) => false + case (PolyType(_, _), _) => false + case (_, MethodType(_, _)) => false + case (_, PolyType(_, _)) => false + case _ => + alwaysMatchSimple || tp1 =:= tp2 + } + } +*/ + + /** Are `syms1' and `syms2' parameter lists with pairwise equivalent types? */ + private def matchingParams(syms1: List[Symbol], syms2: List[Symbol], syms1isJava: Boolean, syms2isJava: Boolean): Boolean = syms1 match { + case Nil => + syms2.isEmpty + case sym1 :: rest1 => + syms2 match { + case Nil => + false + case sym2 :: rest2 => + val tp1 = sym1.tpe + val tp2 = sym2.tpe + (tp1 =:= tp2 || + syms1isJava && tp2.typeSymbol == ObjectClass && tp1.typeSymbol == AnyClass || + syms2isJava && tp1.typeSymbol == ObjectClass && tp2.typeSymbol == AnyClass) && + matchingParams(rest1, rest2, syms1isJava, syms2isJava) + } + } + + /** like map2, but returns list `xs' itself - instead of a copy - if function + * `f' maps all elements to themselves. + */ + def map2Conserve[A <: AnyRef, B](xs: List[A], ys: List[B])(f: (A, B) => A): List[A] = + if (xs.isEmpty) xs + else { + val x1 = f(xs.head, ys.head) + val xs1 = map2Conserve(xs.tail, ys.tail)(f) + if ((x1 eq xs.head) && (xs1 eq xs.tail)) xs + else x1 :: xs1 + } + + /** Solve constraint collected in types `tvars'. + * + * @param tvars All type variables to be instantiated. + * @param tparams The type parameters corresponding to `tvars' + * @param variances The variances of type parameters; need to reverse + * solution direction for all contravariant variables. + * @param upper When `true' search for max solution else min. + */ + def solve(tvars: List[TypeVar], tparams: List[Symbol], + variances: List[Int], upper: Boolean): Boolean = + solve(tvars, tparams, variances, upper, AnyDepth) + + def solve(tvars: List[TypeVar], tparams: List[Symbol], + variances: List[Int], upper: Boolean, depth: Int): Boolean = { + val config = tvars zip (tparams zip variances) + + def solveOne(tvar: TypeVar, tparam: Symbol, variance: Int) { + if (tvar.constr.inst == NoType) { + val up = if (variance != CONTRAVARIANT) upper else !upper + tvar.constr.inst = null + val bound: Type = if (up) tparam.info.bounds.hi else tparam.info.bounds.lo + //Console.println("solveOne0(tv, tp, v, b)="+(tvar, tparam, variance, bound)) + var cyclic = bound contains tparam + for ((tvar2, (tparam2, variance2)) <- config) { + if (tparam2 != tparam && + ((bound contains tparam2) || + up && (tparam2.info.bounds.lo =:= tparam.tpe) || + !up && (tparam2.info.bounds.hi =:= tparam.tpe))) { + if (tvar2.constr.inst eq null) cyclic = true + solveOne(tvar2, tparam2, variance2) + } + } + if (!cyclic) { + if (up) { + if (bound.typeSymbol != AnyClass) + tvar addHiBound bound.instantiateTypeParams(tparams, tvars) + for (tparam2 <- tparams) + tparam2.info.bounds.lo.dealias match { + case TypeRef(_, `tparam`, _) => + tvar addHiBound tparam2.tpe.instantiateTypeParams(tparams, tvars) + case _ => + } + } else { + if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam) { + tvar addLoBound bound.instantiateTypeParams(tparams, tvars) + } + for (tparam2 <- tparams) + tparam2.info.bounds.hi.dealias match { + case TypeRef(_, `tparam`, _) => + tvar addLoBound tparam2.tpe.instantiateTypeParams(tparams, tvars) + case _ => + } + } + } + tvar.constr.inst = NoType // necessary because hibounds/lobounds may contain tvar + + //println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))) + + tvar setInst ( + if (up) { + if (depth != AnyDepth) glb(tvar.constr.hiBounds, depth) else glb(tvar.constr.hiBounds) + } else { + if (depth != AnyDepth) lub(tvar.constr.loBounds, depth) else lub(tvar.constr.loBounds) + }) + + //Console.println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))+" = "+tvar.constr.inst)//@MDEBUG + } + } + + // println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info))) + for ((tvar, (tparam, variance)) <- config) + solveOne(tvar, tparam, variance) + + tvars forall (tvar => tvar.constr.isWithinBounds(tvar.constr.inst)) + } + + /** Do type arguments `targs' conform to formal parameters + * `tparams'? + * + * @param tparams ... + * @param targs ... + * @return ... + */ + def isWithinBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): Boolean = { + var bounds = instantiatedBounds(pre, owner, tparams, targs) + if (targs.exists(_.annotations.nonEmpty)) + bounds = adaptBoundsToAnnotations(bounds, tparams, targs) + (bounds corresponds targs)(_ containsType _) + } + + def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = + tparams map (_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds) + +// Lubs and Glbs --------------------------------------------------------- + + /** The least sorted upwards closed upper bound of a non-empty list + * of lists of types relative to the following ordering <= between lists of types: + * + * xs <= ys iff forall y in ys exists x in xs such that x <: y + * + * @See baseTypeSeq for a definition of sorted and upwards closed. + */ + private def lubList(tss: List[List[Type]], depth: Int): List[Type] = + if (tss.tail.isEmpty) tss.head + else if (tss exists (_.isEmpty)) List() + else { + val ts0 = tss map (_.head) + val sym = minSym(ts0) + if (ts0 forall (_.typeSymbol == sym)) + mergePrefixAndArgs(elimSub(ts0, depth), 1, depth).toList ::: lubList(tss map (_.tail), depth) + else + lubList(tss map (ts => if (ts.head.typeSymbol == sym) ts.tail else ts), depth) + } + + private def lubBaseTypeSeq(tss: List[BaseTypeSeq], depth: Int): List[Type] = + lubList(tss map (_.toList), depth) + + /** The minimal symbol (wrt Symbol.isLess) of a list of types */ + private def minSym(tps: List[Type]): Symbol = + (tps.head.typeSymbol /: tps.tail) { + (sym1, tp2) => if (tp2.typeSymbol isLess sym1) tp2.typeSymbol else sym1 + } + + /** A minimal type list which has a given list of types as its base type sequence */ + def spanningTypes(ts: List[Type]): List[Type] = ts match { + case List() => List() + case first :: rest => + first :: spanningTypes( + rest filter (t => !first.typeSymbol.isSubClass(t.typeSymbol))) + } + + /** Eliminate from list of types all elements which are a supertype + * of some other element of the list. */ + private def elimSuper(ts: List[Type]): List[Type] = ts match { + case List() => List() + case t :: ts1 => + val rest = elimSuper(ts1 filter (t1 => !(t <:< t1))) + if (rest exists (t1 => t1 <:< t)) rest else t :: rest + } + + /** A collector that tests for existential types appearing at given variance in a type */ + class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) { + def traverse(tp: Type) = tp match { + case ExistentialType(_, _) if (variance == v) => result = true + case _ => mapOver(tp) + } + def init() = { + variance = 1 + this + } + } + + val containsCovariantExistentialCollector = new ContainsVariantExistentialCollector(1) + val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1) + + /** Eliminate from list of types all elements which are a subtype + * of some other element of the list. */ + private def elimSub(ts: List[Type], depth: Int): List[Type] = { + def elimAnonymousClass(t: Type) = t match { + case TypeRef(pre, clazz, List()) if clazz.isAnonymousClass => + clazz.classBound.asSeenFrom(pre, clazz.owner) + case _ => + t + } + def elimSub0(ts: List[Type]): List[Type] = ts match { + case List() => List() + case t :: ts1 => + val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, decr(depth)))) + if (rest exists (t1 => isSubType(t, t1, decr(depth)))) rest else t :: rest + } + val ts0 = elimSub0(ts) + if (ts0.isEmpty || ts0.tail.isEmpty) ts0 + else { + val ts1 = ts0 mapConserve (t => elimAnonymousClass(t.underlying)) + if (ts1 eq ts0) ts0 + else elimSub(ts1, depth) + } + } + + private def stripExistentialsAndTypeVars(ts: List[Type]): (List[Type], List[Symbol]) = { + val quantified = ts flatMap { + case ExistentialType(qs, _) => qs + case t => List() + } + def stripType(tp: Type) = tp match { + case ExistentialType(_, res) => + res + case TypeVar(_, constr) => + if (constr.instValid) constr.inst + else abort("trying to do lub/glb of typevar "+tp) + case t => t + } + val strippedTypes = ts mapConserve stripType + (strippedTypes, quantified) + } + + def weakLub(ts: List[Type]) = + if (ts.nonEmpty && (ts forall isNumericValueType)) (numericLub(ts), true) + else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty))) + (annotationsLub(lub(ts map (_.withoutAnnotations)), ts), true) + else (lub(ts), false) + + def weakGlb(ts: List[Type]) = { + if (ts.nonEmpty && (ts forall isNumericValueType)) { + val nglb = numericGlb(ts) + if (nglb != NoType) (nglb, true) + else (glb(ts), false) + } else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty))) { + (annotationsGlb(glb(ts map (_.withoutAnnotations)), ts), true) + } else (glb(ts), false) + } + + def numericLub(ts: List[Type]) = + ts reduceLeft ((t1, t2) => + if (isNumericSubType(t1, t2)) t2 + else if (isNumericSubType(t2, t1)) t1 + else IntClass.tpe) + + def numericGlb(ts: List[Type]) = + ts reduceLeft ((t1, t2) => + if (isNumericSubType(t1, t2)) t1 + else if (isNumericSubType(t2, t1)) t2 + else NoType) + + def isWeakSubType(tp1: Type, tp2: Type) = + tp1.deconst.normalize match { + case TypeRef(_, sym1, _) if isNumericValueClass(sym1) => + tp2.deconst.normalize match { + case TypeRef(_, sym2, _) if isNumericValueClass(sym2) => + isNumericSubClass(sym1, sym2) + case tv2 @ TypeVar(_, _) => + tv2.registerBound(tp1, isLowerBound = true, isNumericBound = true) + case _ => + isSubType(tp1, tp2) + } + case tv1 @ TypeVar(_, _) => + tp2.deconst.normalize match { + case TypeRef(_, sym2, _) if isNumericValueClass(sym2) => + tv1.registerBound(tp2, isLowerBound = false, isNumericBound = true) + case _ => + isSubType(tp1, tp2) + } + case _ => + isSubType(tp1, tp2) + } + + def isNumericSubType(tp1: Type, tp2: Type) = + isNumericValueType(tp1) && isNumericValueType(tp2) && + isNumericSubClass(tp1.typeSymbol, tp2.typeSymbol) + + private val lubResults = new mutable.HashMap[(Int, List[Type]), Type] + private val glbResults = new mutable.HashMap[(Int, List[Type]), Type] + + def lub(ts: List[Type]): Type = try { + lub(ts, lubDepth(ts)) + } finally { + lubResults.clear() + glbResults.clear() + } + + /** The least upper bound wrt <:< of a list of types */ + def lub(ts: List[Type], depth: Int): Type = { + def lub0(ts0: List[Type]): Type = elimSub(ts0, depth) match { + case List() => NothingClass.tpe + case List(t) => t + case ts @ PolyType(tparams, _) :: _ => + val tparams1 = (tparams, matchingBounds(ts, tparams).transpose).zipped map + ((tparam, bounds) => tparam.cloneSymbol.setInfo(glb(bounds, depth))) + PolyType(tparams1, lub0(matchingInstTypes(ts, tparams1))) + case ts @ MethodType(params, _) :: rest => + MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe)))) + case ts @ NullaryMethodType(_) :: rest => + NullaryMethodType(lub0(matchingRestypes(ts, Nil))) + case ts @ TypeBounds(_, _) :: rest => + TypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth)) + case ts => + lubResults get (depth, ts) match { + case Some(lubType) => + lubType + case None => + lubResults((depth, ts)) = AnyClass.tpe + val res = if (depth < 0) AnyClass.tpe else lub1(ts) + lubResults((depth, ts)) = res + res + } + } + def lub1(ts0: List[Type]): Type = { + val (ts, tparams) = stripExistentialsAndTypeVars(ts0) + val bts: List[BaseTypeSeq] = ts map (_.baseTypeSeq) + val lubBaseTypes: List[Type] = lubBaseTypeSeq(bts, depth) + val lubParents = spanningTypes(lubBaseTypes) + val lubOwner = commonOwner(ts) + val lubBase = intersectionType(lubParents, lubOwner) + val lubType = + if (phase.erasedTypes || depth == 0) lubBase + else { + val lubRefined = refinedType(lubParents, lubOwner) + val lubThisType = lubRefined.typeSymbol.thisType + val narrowts = ts map (_.narrow) + def lubsym(proto: Symbol): Symbol = { + val prototp = lubThisType.memberInfo(proto) + val syms = narrowts map (t => + t.nonPrivateMember(proto.name).suchThat(sym => + sym.tpe matches prototp.substThis(lubThisType.typeSymbol, t))) + if (syms contains NoSymbol) NoSymbol + else { + val symtypes = + (narrowts, syms).zipped map ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)) + if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class + proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, decr(depth))) + else if (symtypes.tail forall (symtypes.head =:=)) + proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(symtypes.head) + else { + def lubBounds(bnds: List[TypeBounds]): TypeBounds = + TypeBounds(glb(bnds map (_.lo), decr(depth)), lub(bnds map (_.hi), decr(depth))) + lubRefined.typeSymbol.newAbstractType(proto.pos, proto.name.toTypeName) + .setInfoOwnerAdjusted(lubBounds(symtypes map (_.bounds))) + } + } + } + def refines(tp: Type, sym: Symbol): Boolean = { + val syms = tp.nonPrivateMember(sym.name).alternatives; + !syms.isEmpty && (syms forall (alt => + // todo alt != sym is strictly speaking not correct, but without it we lose + // efficiency. + alt != sym && !specializesSym(lubThisType, sym, tp, alt))) + } + for (sym <- lubBase.nonPrivateMembers) { + // add a refinement symbol for all non-class members of lubBase + // which are refined by every type in ts. + if (!sym.isClass && !sym.isConstructor && (narrowts forall (t => refines(t, sym)))) + try { + val lsym = lubsym(sym) + if (lsym != NoSymbol) addMember(lubThisType, lubRefined, lubsym(sym)) + } catch { + case ex: NoCommonType => + } + } + if (lubRefined.decls.isEmpty) lubBase + else { +// println("refined lub of "+ts+"/"+narrowts+" is "+lubRefined+", baseclasses = "+(ts map (_.baseTypeSeq) map (_.toList))) + lubRefined + } + } + existentialAbstraction(tparams, lubType) + } + if (printLubs) { + println(indent + "lub of " + ts + " at depth "+depth)//debug + indent = indent + " " + assert(indent.length <= 100) + } + val res = lub0(ts) + if (printLubs) { + indent = indent dropRight 2 + println(indent + "lub of " + ts + " is " + res)//debug + } + if (ts forall (_.isNotNull)) res.notNull else res + } + + val GlbFailure = new Throwable + + /** A global counter for glb calls in the `specializes' query connected to the `addMembers' + * call in `glb'. There's a possible infinite recursion when `specializes' calls + * memberType, which calls baseTypeSeq, which calls mergePrefixAndArgs, which calls glb. + * The counter breaks this recursion after two calls. + * If the recursion is broken, no member is added to the glb. + */ + private var globalGlbDepth = 0 + private final val globalGlbLimit = 2 + + def glb(ts: List[Type]): Type = try { + glb(ts, lubDepth(ts)) + } finally { + lubResults.clear() + glbResults.clear() + } + + /** The greatest lower bound wrt <:< of a list of types */ + private def glb(ts: List[Type], depth: Int): Type = { + def glb0(ts0: List[Type]): Type = elimSuper(ts0) match { + case List() => AnyClass.tpe + case List(t) => t + case ts @ PolyType(tparams, _) :: _ => + val tparams1 = (tparams, matchingBounds(ts, tparams).transpose).zipped map + ((tparam, bounds) => tparam.cloneSymbol.setInfo(lub(bounds, depth))) + PolyType(tparams1, glb0(matchingInstTypes(ts, tparams1))) + case ts @ MethodType(params, _) :: rest => + MethodType(params, glb0(matchingRestypes(ts, params map (_.tpe)))) + case ts @ NullaryMethodType(_) :: rest => + NullaryMethodType(glb0(matchingRestypes(ts, Nil))) + case ts @ TypeBounds(_, _) :: rest => + TypeBounds(lub(ts map (_.bounds.lo), depth), glb(ts map (_.bounds.hi), depth)) + case ts => + glbResults get (depth, ts) match { + case Some(glbType) => + glbType + case _ => + glbResults((depth, ts)) = NothingClass.tpe + val res = if (depth < 0) NothingClass.tpe else glb1(ts) + glbResults((depth, ts)) = res + res + } + } + def glb1(ts0: List[Type]): Type = { + try { + val (ts, tparams) = stripExistentialsAndTypeVars(ts0) + val glbOwner = commonOwner(ts) + def refinedToParents(t: Type): List[Type] = t match { + case RefinedType(ps, _) => ps flatMap refinedToParents + case _ => List(t) + } + def refinedToDecls(t: Type): List[Scope] = t match { + case RefinedType(ps, decls) => + val dss = ps flatMap refinedToDecls + if (decls.isEmpty) dss else decls :: dss + case _ => List() + } + val ts1 = ts flatMap refinedToParents + val glbBase = intersectionType(ts1, glbOwner) + val glbType = + if (phase.erasedTypes || depth == 0) glbBase + else { + val glbRefined = refinedType(ts1, glbOwner) + val glbThisType = glbRefined.typeSymbol.thisType + def glbsym(proto: Symbol): Symbol = { + val prototp = glbThisType.memberInfo(proto) + val syms = for (t <- ts; + alt <- (t.nonPrivateMember(proto.name).alternatives); + if glbThisType.memberInfo(alt) matches prototp + ) yield alt + val symtypes = syms map glbThisType.memberInfo + assert(!symtypes.isEmpty) + proto.cloneSymbol(glbRefined.typeSymbol).setInfoOwnerAdjusted( + if (proto.isTerm) glb(symtypes, decr(depth)) + else { + def isTypeBound(tp: Type) = tp match { + case TypeBounds(_, _) => true + case _ => false + } + def glbBounds(bnds: List[Type]): TypeBounds = { + val lo = lub(bnds map (_.bounds.lo), decr(depth)) + val hi = glb(bnds map (_.bounds.hi), decr(depth)) + if (lo <:< hi) TypeBounds(lo, hi) + else throw GlbFailure + } + val symbounds = symtypes filter isTypeBound + var result: Type = + if (symbounds.isEmpty) + TypeBounds.empty + else glbBounds(symbounds) + for (t <- symtypes if !isTypeBound(t)) + if (result.bounds containsType t) result = t + else throw GlbFailure + result + }) + } + if (globalGlbDepth < globalGlbLimit) + try { + globalGlbDepth += 1 + val dss = ts flatMap refinedToDecls + for (ds <- dss; val sym <- ds.iterator) + if (globalGlbDepth < globalGlbLimit && !(glbThisType specializes sym)) + try { + addMember(glbThisType, glbRefined, glbsym(sym)) + } catch { + case ex: NoCommonType => + } + } finally { + globalGlbDepth -= 1 + } + if (glbRefined.decls.isEmpty) glbBase else glbRefined + } + existentialAbstraction(tparams, glbType) + } catch { + case GlbFailure => + if (ts forall (t => NullClass.tpe <:< t)) NullClass.tpe + else NothingClass.tpe + } + } + // if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG + + val res = glb0(ts) + + // if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG + + if (ts exists (_.isNotNull)) res.notNull else res + } + + /** The most deeply nested owner that contains all the symbols + * of thistype or prefixless typerefs/singletype occurrences in given type. + */ + private def commonOwner(t: Type): Symbol = { + commonOwnerMap.init + commonOwnerMap.apply(t) + commonOwnerMap.result + } + + /** The most deeply nested owner that contains all the symbols + * of thistype or prefixless typerefs/singletype occurrences in given list + * of types. + */ + private def commonOwner(tps: List[Type]): Symbol = { + // if (settings.debug.value) log("computing common owner of types " + tps)//DEBUG + commonOwnerMap.init + tps foreach { tp => commonOwnerMap.apply(tp); () } + commonOwnerMap.result + } + + /** Compute lub (if variance == 1) or glb (if variance == -1) of given list + * of types `tps'. All types in `tps' are typerefs or singletypes + * with the same symbol. + * Return `Some(x)' if the computation succeeds with result `x'. + * Return `None' if the computation fails. + */ + def mergePrefixAndArgs(tps: List[Type], variance: Int, depth: Int): Option[Type] = tps match { + case List(tp) => + Some(tp) + case TypeRef(_, sym, _) :: rest => + val pres = tps map (_.prefix) // prefix normalizes automatically + val pre = if (variance == 1) lub(pres, depth) else glb(pres, depth) + val argss = tps map (_.normalize.typeArgs) // symbol equality (of the tp in tps) was checked using typeSymbol, which normalizes, so should normalize before retrieving arguments + val capturedParams = new ListBuffer[Symbol] + try { + if (sym == ArrayClass && phase.erasedTypes) { + // special treatment for lubs of array types after erasure: + // if argss contain one value type and some other type, the lub is Object + // if argss contain several reference types, the lub is an array over lub of argtypes + if (argss exists (_.isEmpty)) { + None // something is wrong: an array without a type arg. + } else { + val args = argss map (_.head) + if (args.tail forall (_ =:= args.head)) Some(typeRef(pre, sym, List(args.head))) + else if (args exists (arg => isValueClass(arg.typeSymbol))) Some(ObjectClass.tpe) + else Some(typeRef(pre, sym, List(lub(args)))) + } + } else { + val args = (sym.typeParams, argss.transpose).zipped map { + (tparam, as) => + if (depth == 0) + if (tparam.variance == variance) AnyClass.tpe + else if (tparam.variance == -variance) NothingClass.tpe + else NoType + else + if (tparam.variance == variance) lub(as, decr(depth)) + else if (tparam.variance == -variance) glb(as, decr(depth)) + else { + val l = lub(as, decr(depth)) + val g = glb(as, decr(depth)) + if (l <:< g) l + else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we + // just err on the conservative side, i.e. with a bound that is too high. + // if(!(tparam.info.bounds contains tparam)){ //@M can't deal with f-bounds, see #2251 + + val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l) + capturedParams += qvar + qvar.tpe + } + } + } + if (args contains NoType) None + else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args))) + } + } catch { + case ex: MalformedType => None + case ex: IndexOutOfBoundsException => // transpose freaked out because of irregular argss + // catching just in case (shouldn't happen, but also doesn't cost us) + if (settings.debug.value) log("transposed irregular matrix!?"+ (tps, argss)) + None + } + case SingleType(_, sym) :: rest => + val pres = tps map (_.prefix) + val pre = if (variance == 1) lub(pres, depth) else glb(pres, depth) + try { + Some(singleType(pre, sym)) + } catch { + case ex: MalformedType => None + } + case ExistentialType(tparams, quantified) :: rest => + mergePrefixAndArgs(quantified :: rest, variance, depth) map (existentialAbstraction(tparams, _)) + case _ => + assert(false, tps); None + } + + /** Make symbol `sym' a member of scope `tp.decls' + * where `thistp' is the narrowed owner type of the scope. + */ + def addMember(thistp: Type, tp: Type, sym: Symbol) { + assert(sym != NoSymbol) + // if (settings.debug.value) log("add member " + sym+":"+sym.info+" to "+thistp) //DEBUG + if (!(thistp specializes sym)) { + if (sym.isTerm) + for (alt <- tp.nonPrivateDecl(sym.name).alternatives) + if (specializesSym(thistp, sym, thistp, alt)) + tp.decls unlink alt; + tp.decls enter sym + } + } + + /** All types in list must be polytypes with type parameter lists of + * same length as tparams. + * Returns list of list of bounds infos, where corresponding type + * parameters are renamed to tparams. + */ + private def matchingBounds(tps: List[Type], tparams: List[Symbol]): List[List[Type]] = + tps map { + case PolyType(tparams1, _) if sameLength(tparams1, tparams) => + tparams1 map (tparam => tparam.info.substSym(tparams1, tparams)) + case _ => + throw new NoCommonType(tps) + } + + /** All types in list must be polytypes with type parameter lists of + * same length as tparams. + * Returns list of instance types, where corresponding type + * parameters are renamed to tparams. + */ + private def matchingInstTypes(tps: List[Type], tparams: List[Symbol]): List[Type] = + tps map { + case PolyType(tparams1, restpe) if sameLength(tparams1, tparams) => + restpe.substSym(tparams1, tparams) + case _ => + throw new NoCommonType(tps) + } + + /** All types in list must be method types with equal parameter types. + * Returns list of their result types. + */ + private def matchingRestypes(tps: List[Type], pts: List[Type]): List[Type] = + tps map { + case MethodType(params1, res) if (isSameTypes(params1 map (_.tpe), pts)) => + res + case NullaryMethodType(res) if pts isEmpty => + res + case _ => + throw new NoCommonType(tps) + } + + +// TODO: this desperately needs to be cleaned up +// plan: split into kind inference and subkinding +// every Type has a (cached) Kind + def kindsConform(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): Boolean = checkKindBounds0(tparams, targs, pre, owner, false).isEmpty + + /** Check well-kindedness of type application (assumes arities are already checked) -- @M + * + * This check is also performed when abstract type members become concrete (aka a "type alias") -- then tparams.length==1 + * (checked one type member at a time -- in that case, prefix is the name of the type alias) + * + * Type application is just like value application: it's "contravariant" in the sense that + * the type parameters of the supplied type arguments must conform to the type parameters of + * the required type parameters: + * - their bounds must be less strict + * - variances must match (here, variances are absolute, the variance of a type parameter does not influence the variance of its higher-order parameters) + * - @M TODO: are these conditions correct,sufficient&necessary? + * + * e.g. class Iterable[t, m[+x <: t]] --> the application Iterable[Int, List] is okay, since + * List's type parameter is also covariant and its bounds are weaker than <: Int + */ + def checkKindBounds0(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol, explainErrors: Boolean): List[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] = { + var error = false + + def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz) // instantiate type params that come from outside the abstract type we're currently checking + def transformedBounds(p: Symbol, o: Symbol) = transform(p.info.instantiateTypeParams(tparams, targs).bounds, o) + + /** Check whether <arg>sym1</arg>'s variance conforms to <arg>sym2</arg>'s variance + * + * If <arg>sym2</arg> is invariant, <arg>sym1</arg>'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</arg> to a higher-kinded type conform to the expected params <arg>hkparams</arg> + 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) + if (!(bindHKParams(transformedBounds(hkparam, paramowner)) <:< transform(hkarg.info.bounds, owner))) + stricterBound(hkarg, hkparam) + + if (settings.debug.value) { + log("checkKindBoundsHK base case: "+ hkparam +" declared bounds: "+ transformedBounds(hkparam, paramowner) +" after instantiating earlier hkparams: "+ bindHKParams(transformedBounds(hkparam, paramowner))) + log("checkKindBoundsHK base case: "+ hkarg +" has bounds: "+ transform(hkarg.info.bounds, owner)) + } + } 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)])] + (tparams zip targs).foreach{ case (tparam, targ) if (targ.isHigherKinded || !tparam.typeParams.isEmpty) => + // @M must use the typeParams of the type targ, not the typeParams of the symbol of targ!! + targ.typeSymbolDirect.info // force symbol load for #4205 + val tparamsHO = targ.typeParams + + val (arityMismatches, varianceMismatches, stricterBounds) = + checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) // NOTE: *not* targ.typeSymbol, which normalizes + + if(!explainErrors) {if(error) return List((NoType, NoSymbol, Nil, Nil, Nil))} + else if (arityMismatches.nonEmpty || varianceMismatches.nonEmpty || stricterBounds.nonEmpty) { + errors += ((targ, tparam, arityMismatches, varianceMismatches, stricterBounds)) + } + // case (tparam, targ) => println("no check: "+(tparam, targ, tparam.typeParams.isEmpty)) + case _ => + } + + 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") + + + /** The maximum number of recursions allowed in toString + */ + final val maxTostringRecursions = 50 + + private var tostringRecursions = 0 +} diff --git a/src/compiler/scala/reflect/common/pickling/UnPickler.scala b/src/compiler/scala/reflect/common/pickling/UnPickler.scala new file mode 100644 index 0000000000..6b0f933f9b --- /dev/null +++ b/src/compiler/scala/reflect/common/pickling/UnPickler.scala @@ -0,0 +1,841 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package common +package pickling + +import java.io.IOException +import java.lang.Float.intBitsToFloat +import java.lang.Double.longBitsToDouble + +import Flags._ +import PickleFormat._ +import collection.mutable.{HashMap, ListBuffer} +import annotation.switch + +/** @author Martin Odersky + * @version 1.0 + */ +abstract class UnPickler /*extends reflect.generic.UnPickler*/ { + val global: SymbolTable + import global._ + + /** Unpickle symbol table information descending from a class and/or module root + * from an array of bytes. + * @param bytes bytearray from which we unpickle + * @param offset offset from which unpickling starts + * @param classroot the top-level class which is unpickled, or NoSymbol if inapplicable + * @param moduleroot the top-level module which is unpickled, or NoSymbol if inapplicable + * @param filename filename associated with bytearray, only used for error messages + */ + def unpickle(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) { + try { + new Scan(bytes, offset, classRoot, moduleRoot, filename).run() + } catch { + case ex: IOException => + throw ex + case ex: Throwable => + /*if (settings.debug.value)*/ ex.printStackTrace() + throw new RuntimeException("error reading Scala signature of "+filename+": "+ex.getMessage()) + } + } + + class Scan(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) extends PickleBuffer(bytes, offset, -1) { + //println("unpickle " + classRoot + " and " + moduleRoot)//debug + + protected def debug = settings.debug.value + + checkVersion() + + /** A map from entry numbers to array offsets */ + private val index = createIndex + + /** A map from entry numbers to symbols, types, or annotations */ + private val entries = new Array[AnyRef](index.length) + + /** A map from symbols to their associated `decls' scopes */ + private val symScopes = new HashMap[Symbol, Scope] + + //println("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug + + def run() { + // read children last, fix for #3951 + val queue = new collection.mutable.ListBuffer[() => Unit]() + def delay(i: Int, action: => Unit) { + queue += (() => at(i, {() => action; null})) + } + + for (i <- 0 until index.length) { + if (isSymbolEntry(i)) + at(i, readSymbol) + else if (isSymbolAnnotationEntry(i)) + delay(i, readSymbolAnnotation()) + else if (isChildrenEntry(i)) + delay(i, readChildren()) + } + + for (action <- queue) + action() + } + + private def checkVersion() { + val major = readNat() + val minor = readNat() + if (major != MajorVersion || minor > MinorVersion) + throw new IOException("Scala signature " + classRoot.decodedName + + " has wrong version\n expected: " + + MajorVersion + "." + MinorVersion + + "\n found: " + major + "." + minor + + " in "+filename) + } + + /** The `decls' scope associated with given symbol */ + protected def symScope(sym: Symbol) = symScopes.getOrElseUpdate(sym, newScope) + + /** Does entry represent an (internal) symbol */ + protected def isSymbolEntry(i: Int): Boolean = { + val tag = bytes(index(i)).toInt + (firstSymTag <= tag && tag <= lastSymTag && + (tag != CLASSsym || !isRefinementSymbolEntry(i))) + } + + /** Does entry represent an (internal or external) symbol */ + protected def isSymbolRef(i: Int): Boolean = { + val tag = bytes(index(i)) + (firstSymTag <= tag && tag <= lastExtSymTag) + } + + /** Does entry represent a name? */ + protected def isNameEntry(i: Int): Boolean = { + val tag = bytes(index(i)).toInt + tag == TERMname || tag == TYPEname + } + + /** Does entry represent a symbol annotation? */ + protected def isSymbolAnnotationEntry(i: Int): Boolean = { + val tag = bytes(index(i)).toInt + tag == SYMANNOT + } + + /** Does the entry represent children of a symbol? */ + protected def isChildrenEntry(i: Int): Boolean = { + val tag = bytes(index(i)).toInt + tag == CHILDREN + } + + /** Does entry represent a refinement symbol? + * pre: Entry is a class symbol + */ + protected def isRefinementSymbolEntry(i: Int): Boolean = { + val savedIndex = readIndex + readIndex = index(i) + val tag = readByte().toInt + assert(tag == CLASSsym) + + readNat(); // read length + val result = readNameRef() == tpnme.REFINE_CLASS_NAME + readIndex = savedIndex + result + } + + /** If entry at <code>i</code> is undefined, define it by performing + * operation <code>op</code> with <code>readIndex at start of i'th + * entry. Restore <code>readIndex</code> afterwards. + */ + protected def at[T <: AnyRef](i: Int, op: () => T): T = { + var r = entries(i) + if (r eq null) { + val savedIndex = readIndex + readIndex = index(i) + r = op() + assert(entries(i) eq null, entries(i)) + entries(i) = r + readIndex = savedIndex + } + r.asInstanceOf[T] + } + + /** Read a name */ + protected def readName(): Name = { + val tag = readByte() + val len = readNat() + tag match { + case TERMname => newTermName(bytes, readIndex, len) + case TYPEname => newTypeName(bytes, readIndex, len) + case _ => errorBadSignature("bad name tag: " + tag) + } + } + + /** Read a symbol */ + protected def readSymbol(): Symbol = { + val tag = readByte() + val end = readNat() + readIndex + def atEnd = readIndex == end + + def readExtSymbol(): Symbol = { + val name = readNameRef() + val owner = if (atEnd) definitions.RootClass else readSymbolRef() + + def fromName(name: Name) = mkTermName(name) match { + case nme.ROOT => definitions.RootClass + case nme.ROOTPKG => definitions.RootPackage + case _ => + val s = owner.info.decl(name) + if (tag == EXTref) s else s.moduleClass + } + def nestedObjectSymbol: Symbol = { + // If the owner is overloaded (i.e. a method), it's not possible to select the + // right member, so return NoSymbol. This can only happen when unpickling a tree. + // the "case Apply" in readTree() takes care of selecting the correct alternative + // after parsing the arguments. + if (owner.isOverloaded) + return NoSymbol + + if (tag == EXTMODCLASSref) { + val moduleVar = owner.info.decl(nme.moduleVarName(name)) + if (moduleVar.isLazyAccessor) + return moduleVar.lazyAccessor.lazyAccessor + } + NoSymbol + } + + // (1) Try name. + fromName(name) orElse { + // (2) Try with expanded name. Can happen if references to private + // symbols are read from outside: for instance when checking the children + // of a class. See #1722. + fromName(nme.expandedName(name, owner)) orElse { + // (3) Try as a nested object symbol. + nestedObjectSymbol orElse { + // (4) Otherwise, fail. + errorMissingRequirement(name, owner) + } + } + } + } + + tag match { + case NONEsym => return NoSymbol + case EXTref | EXTMODCLASSref => return readExtSymbol() + case _ => () + } + + // symbols that were pickled with Pickler.writeSymInfo + val nameref = readNat() + val name = at(nameref, readName) + val owner = readSymbolRef() + val flags = pickledToRawFlags(readLongNat()) + var inforef = readNat() + val privateWithin = + if (!isSymbolRef(inforef)) NoSymbol + else { + val pw = at(inforef, readSymbol) + inforef = readNat() + pw + } + + def isModuleFlag = (flags & MODULE) != 0L + def isMethodFlag = (flags & METHOD) != 0L + def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) + def isModuleRoot = (name == moduleRoot.name) && (owner == moduleRoot.owner) + + def finishSym(sym: Symbol): Symbol = { + sym.flags = flags & PickledFlags + sym.privateWithin = privateWithin + sym.info = ( + if (atEnd) { + assert(!sym.isSuperAccessor, sym) + newLazyTypeRef(inforef) + } + else { + assert(sym.isSuperAccessor || sym.isParamAccessor, sym) + newLazyTypeRefAndAlias(inforef, readNat()) + } + ) + if (sym.owner.isClass && sym != classRoot && sym != moduleRoot && + !sym.isModuleClass && !sym.isRefinementClass && !sym.isTypeParameter && !sym.isExistentiallyBound) + symScope(sym.owner) enter sym + + sym + } + + finishSym(tag match { + case TYPEsym => owner.newAbstractType(mkTypeName(name)) + case ALIASsym => owner.newAliasType(mkTypeName(name)) + case CLASSsym => + val sym = (isClassRoot, isModuleFlag) match { + case (true, true) => moduleRoot.moduleClass + case (true, false) => classRoot + case (false, true) => owner.newModuleClass(mkTypeName(name)) + case (false, false) => owner.newClass(mkTypeName(name)) + } + if (!atEnd) + sym.typeOfThis = newLazyTypeRef(readNat()) + + sym + case MODULEsym => + val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... () + if (isModuleRoot) moduleRoot + else { + val m = owner.newModule(name, clazz) + clazz.sourceModule = m + m + } + case VALsym => + if (isModuleRoot) { assert(false); NoSymbol } + else if (isMethodFlag) owner.newMethod(name) + else owner.newValue(name) + + case _ => + errorBadSignature("bad symbol tag: " + tag) + }) + } + + /** Read a type + * + * @param forceProperType is used to ease the transition to NullaryMethodTypes (commentmarker: NMT_TRANSITION) + * the flag say that a type of kind * is expected, so that PolyType(tps, restpe) can be disambiguated to PolyType(tps, NullaryMethodType(restpe)) + * (if restpe is not a ClassInfoType, a MethodType or a NullaryMethodType, which leaves TypeRef/SingletonType -- the latter would make the polytype a type constructor) + */ + protected def readType(forceProperType: Boolean = false): Type = { + val tag = readByte() + val end = readNat() + readIndex + (tag: @switch) match { + case NOtpe => + NoType + case NOPREFIXtpe => + NoPrefix + case THIStpe => + ThisType(readSymbolRef()) + case SINGLEtpe => + SingleType(readTypeRef(), readSymbolRef()) // !!! was singleType + case SUPERtpe => + val thistpe = readTypeRef() + val supertpe = readTypeRef() + SuperType(thistpe, supertpe) + case CONSTANTtpe => + ConstantType(readConstantRef()) + case TYPEREFtpe => + val pre = readTypeRef() + val sym = readSymbolRef() + var args = until(end, readTypeRef) + TypeRef(pre, sym, args) + case TYPEBOUNDStpe => + TypeBounds(readTypeRef(), readTypeRef()) + case REFINEDtpe => + val clazz = readSymbolRef() + RefinedType(until(end, readTypeRef), symScope(clazz), clazz) + case CLASSINFOtpe => + val clazz = readSymbolRef() + ClassInfoType(until(end, readTypeRef), symScope(clazz), clazz) + case METHODtpe | IMPLICITMETHODtpe => + val restpe = readTypeRef() + val params = until(end, readSymbolRef) + // if the method is overloaded, the params cannot be determined (see readSymbol) => return NoType. + // Only happen for trees, "case Apply" in readTree() takes care of selecting the correct + // alternative after parsing the arguments. + if (params.contains(NoSymbol) || restpe == NoType) NoType + else MethodType(params, restpe) + case POLYtpe => + val restpe = readTypeRef() + val typeParams = until(end, readSymbolRef) + if(typeParams nonEmpty) { + // NMT_TRANSITION: old class files denoted a polymorphic nullary method as PolyType(tps, restpe), we now require PolyType(tps, NullaryMethodType(restpe)) + // when a type of kind * is expected (forceProperType is true), we know restpe should be wrapped in a NullaryMethodType (if it wasn't suitably wrapped yet) + def transitionNMT(restpe: Type) = { + val resTpeCls = restpe.getClass.toString // what's uglier than isInstanceOf? right! -- isInstanceOf does not work since the concrete types are defined in the compiler (not in scope here) + if(forceProperType /*&& pickleformat < 2.9 */ && !(resTpeCls.endsWith("MethodType"))) { assert(!resTpeCls.contains("ClassInfoType")) + NullaryMethodType(restpe) } + else restpe + } + PolyType(typeParams, transitionNMT(restpe)) + } + else + NullaryMethodType(restpe) + case EXISTENTIALtpe => + val restpe = readTypeRef() + ExistentialType(until(end, readSymbolRef), restpe) + case ANNOTATEDtpe => + var typeRef = readNat() + val selfsym = if (isSymbolRef(typeRef)) { + val s = at(typeRef, readSymbol) + typeRef = readNat() + s + } else NoSymbol // selfsym can go. + val tp = at(typeRef, () => readType(forceProperType)) // NMT_TRANSITION + val annots = until(end, readAnnotationRef) + if (selfsym == NoSymbol) AnnotatedType(annots, tp, selfsym) + else tp + case _ => + noSuchTypeTag(tag, end) + } + } + + def noSuchTypeTag(tag: Int, end: Int): Type = + errorBadSignature("bad type tag: " + tag) + + /** Read a constant */ + protected def readConstant(): Constant = { + val tag = readByte().toInt + val len = readNat() + (tag: @switch) match { + case LITERALunit => Constant(()) + case LITERALboolean => Constant(readLong(len) != 0L) + case LITERALbyte => Constant(readLong(len).toByte) + case LITERALshort => Constant(readLong(len).toShort) + case LITERALchar => Constant(readLong(len).toChar) + case LITERALint => Constant(readLong(len).toInt) + case LITERALlong => Constant(readLong(len)) + case LITERALfloat => Constant(intBitsToFloat(readLong(len).toInt)) + case LITERALdouble => Constant(longBitsToDouble(readLong(len))) + case LITERALstring => Constant(readNameRef().toString()) + case LITERALnull => Constant(null) + case LITERALclass => Constant(readTypeRef()) + case LITERALenum => Constant(readSymbolRef()) + case _ => noSuchConstantTag(tag, len) + } + } + + def noSuchConstantTag(tag: Int, len: Int): Constant = + errorBadSignature("bad constant tag: " + tag) + + /** Read children and store them into the corresponding symbol. + */ + protected def readChildren() { + val tag = readByte() + assert(tag == CHILDREN) + val end = readNat() + readIndex + val target = readSymbolRef() + while (readIndex != end) target addChild readSymbolRef() + } + + /** Read an annotation argument, which is pickled either + * as a Constant or a Tree. + */ + protected def readAnnotArg(i: Int): Tree = bytes(index(i)) match { + case TREE => at(i, readTree) + case _ => + val const = at(i, readConstant) + Literal(const) setType const.tpe + } + + /** Read a ClassfileAnnotArg (argument to a classfile annotation) + */ + private def readArrayAnnot() = { + readByte() // skip the `annotargarray` tag + val end = readNat() + readIndex + until(end, () => readClassfileAnnotArg(readNat())).toArray(classfileAnnotArgManifest) + } + protected def readClassfileAnnotArg(i: Int): ClassfileAnnotArg = bytes(index(i)) match { + case ANNOTINFO => NestedAnnotArg(at(i, readAnnotation)) + case ANNOTARGARRAY => at(i, () => ArrayAnnotArg(readArrayAnnot())) + case _ => LiteralAnnotArg(at(i, readConstant)) + } + + /** Read an AnnotationInfo. Not to be called directly, use + * readAnnotation or readSymbolAnnotation + */ + protected def readAnnotationInfo(end: Int): AnnotationInfo = { + val atp = readTypeRef() + val args = new ListBuffer[Tree] + val assocs = new ListBuffer[(Name, ClassfileAnnotArg)] + while (readIndex != end) { + val argref = readNat() + if (isNameEntry(argref)) { + val name = at(argref, readName) + val arg = readClassfileAnnotArg(readNat()) + assocs += ((name, arg)) + } + else + args += readAnnotArg(argref) + } + AnnotationInfo(atp, args.toList, assocs.toList) + } + + /** Read an annotation and as a side effect store it into + * the symbol it requests. Called at top-level, for all + * (symbol, annotInfo) entries. */ + protected def readSymbolAnnotation() { + val tag = readByte() + if (tag != SYMANNOT) + errorBadSignature("symbol annotation expected ("+ tag +")") + val end = readNat() + readIndex + val target = readSymbolRef() + target.addAnnotation(readAnnotationInfo(end)) + } + + /** Read an annotation and return it. Used when unpickling + * an ANNOTATED(WSELF)tpe or a NestedAnnotArg */ + protected def readAnnotation(): AnnotationInfo = { + val tag = readByte() + if (tag != ANNOTINFO) + errorBadSignature("annotation expected (" + tag + ")") + val end = readNat() + readIndex + readAnnotationInfo(end) + } + + /* Read an abstract syntax tree */ + protected def readTree(): Tree = { + val outerTag = readByte() + if (outerTag != TREE) + errorBadSignature("tree expected (" + outerTag + ")") + val end = readNat() + readIndex + val tag = readByte() + val tpe = if (tag == EMPTYtree) NoType else readTypeRef() + + // Set by the three functions to follow. If symbol is non-null + // after the the new tree 't' has been created, t has its Symbol + // set to symbol; and it always has its Type set to tpe. + var symbol: Symbol = null + var mods: Modifiers = null + var name: Name = null + + /** Read a Symbol, Modifiers, and a Name */ + def setSymModsName() { + symbol = readSymbolRef() + mods = readModifiersRef() + name = readNameRef() + } + /** Read a Symbol and a Name */ + def setSymName() { + symbol = readSymbolRef() + name = readNameRef() + } + /** Read a Symbol */ + def setSym() { + symbol = readSymbolRef() + } + + val t = tag match { + case EMPTYtree => + EmptyTree + + case PACKAGEtree => + setSym() + val pid = readTreeRef().asInstanceOf[RefTree] + val stats = until(end, readTreeRef) + PackageDef(pid, stats) + + case CLASStree => + setSymModsName() + val impl = readTemplateRef() + val tparams = until(end, readTypeDefRef) + ClassDef(mods, mkTypeName(name), tparams, impl) + + case MODULEtree => + setSymModsName() + ModuleDef(mods, name, readTemplateRef()) + + case VALDEFtree => + setSymModsName() + val tpt = readTreeRef() + val rhs = readTreeRef() + ValDef(mods, name, tpt, rhs) + + case DEFDEFtree => + setSymModsName() + val tparams = times(readNat(), readTypeDefRef) + val vparamss = times(readNat(), () => times(readNat(), readValDefRef)) + val tpt = readTreeRef() + val rhs = readTreeRef() + DefDef(mods, name, tparams, vparamss, tpt, rhs) + + case TYPEDEFtree => + setSymModsName() + val rhs = readTreeRef() + val tparams = until(end, readTypeDefRef) + TypeDef(mods, mkTypeName(name), tparams, rhs) + + case LABELtree => + setSymName() + val rhs = readTreeRef() + val params = until(end, readIdentRef) + LabelDef(name, params, rhs) + + case IMPORTtree => + setSym() + val expr = readTreeRef() + val selectors = until(end, () => { + val from = readNameRef() + val to = readNameRef() + ImportSelector(from, -1, to, -1) + }) + + Import(expr, selectors) + + case TEMPLATEtree => + setSym() + val parents = times(readNat(), readTreeRef) + val self = readValDefRef() + val body = until(end, readTreeRef) + + Template(parents, self, body) + + case BLOCKtree => + val expr = readTreeRef() + val stats = until(end, readTreeRef) + Block(stats, expr) + + case CASEtree => + val pat = readTreeRef() + val guard = readTreeRef() + val body = readTreeRef() + CaseDef(pat, guard, body) + + case ALTERNATIVEtree => + Alternative(until(end, readTreeRef)) + + case STARtree => + Star(readTreeRef()) + + case BINDtree => + setSymName() + Bind(name, readTreeRef()) + + case UNAPPLYtree => + val fun = readTreeRef() + val args = until(end, readTreeRef) + UnApply(fun, args) + + case ARRAYVALUEtree => + val elemtpt = readTreeRef() + val trees = until(end, readTreeRef) + ArrayValue(elemtpt, trees) + + case FUNCTIONtree => + setSym() + val body = readTreeRef() + val vparams = until(end, readValDefRef) + Function(vparams, body) + + case ASSIGNtree => + val lhs = readTreeRef() + val rhs = readTreeRef() + Assign(lhs, rhs) + + case IFtree => + val cond = readTreeRef() + val thenp = readTreeRef() + val elsep = readTreeRef() + If(cond, thenp, elsep) + + case MATCHtree => + val selector = readTreeRef() + val cases = until(end, readCaseDefRef) + Match(selector, cases) + + case RETURNtree => + setSym() + Return(readTreeRef()) + + case TREtree => + val block = readTreeRef() + val finalizer = readTreeRef() + val catches = until(end, readCaseDefRef) + Try(block, catches, finalizer) + + case THROWtree => + Throw(readTreeRef()) + + case NEWtree => + New(readTreeRef()) + + case TYPEDtree => + val expr = readTreeRef() + val tpt = readTreeRef() + Typed(expr, tpt) + + case TYPEAPPLYtree => + val fun = readTreeRef() + val args = until(end, readTreeRef) + TypeApply(fun, args) + + case APPLYtree => + val fun = readTreeRef() + val args = until(end, readTreeRef) + if (fun.symbol.isOverloaded) { + fun.setType(fun.symbol.info) + inferMethodAlternative(fun, args map (_.tpe), tpe) + } + Apply(fun, args) + + case APPLYDYNAMICtree => + setSym() + val qual = readTreeRef() + val args = until(end, readTreeRef) + ApplyDynamic(qual, args) + + case SUPERtree => + setSym() + val qual = readTreeRef() + val mix = readTypeNameRef() + Super(qual, mix) + + case THIStree => + setSym() + This(readTypeNameRef()) + + case SELECTtree => + setSym() + val qualifier = readTreeRef() + val selector = readNameRef() + Select(qualifier, selector) + + case IDENTtree => + setSymName() + Ident(name) + + case LITERALtree => + Literal(readConstantRef()) + + case TYPEtree => + TypeTree() + + case ANNOTATEDtree => + val annot = readTreeRef() + val arg = readTreeRef() + Annotated(annot, arg) + + case SINGLETONTYPEtree => + SingletonTypeTree(readTreeRef()) + + case SELECTFROMTYPEtree => + val qualifier = readTreeRef() + val selector = readTypeNameRef() + SelectFromTypeTree(qualifier, selector) + + case COMPOUNDTYPEtree => + CompoundTypeTree(readTemplateRef()) + + case APPLIEDTYPEtree => + val tpt = readTreeRef() + val args = until(end, readTreeRef) + AppliedTypeTree(tpt, args) + + case TYPEBOUNDStree => + val lo = readTreeRef() + val hi = readTreeRef() + TypeBoundsTree(lo, hi) + + case EXISTENTIALTYPEtree => + val tpt = readTreeRef() + val whereClauses = until(end, readTreeRef) + ExistentialTypeTree(tpt, whereClauses) + + case _ => + noSuchTreeTag(tag, end) + } + + if (symbol == null) t setType tpe + else t setSymbol symbol setType tpe + } + + def noSuchTreeTag(tag: Int, end: Int) = + errorBadSignature("unknown tree type (" + tag + ")") + + def readModifiers(): Modifiers = { + val tag = readNat() + if (tag != MODIFIERS) + errorBadSignature("expected a modifiers tag (" + tag + ")") + val end = readNat() + readIndex + val pflagsHi = readNat() + val pflagsLo = readNat() + val pflags = (pflagsHi.toLong << 32) + pflagsLo + val flags = pickledToRawFlags(pflags) + val privateWithin = readNameRef() + Modifiers(flags, privateWithin, Nil, Map.empty) + } + + /* Read a reference to a pickled item */ + protected def readNameRef(): Name = at(readNat(), readName) + protected def readSymbolRef(): Symbol = at(readNat(), readSymbol) + protected def readTypeRef(): Type = at(readNat(), () => readType()) // after the NMT_TRANSITION period, we can leave off the () => ... () + protected def readConstantRef(): Constant = at(readNat(), readConstant) + protected def readAnnotationRef(): AnnotationInfo = at(readNat(), readAnnotation) + protected def readModifiersRef(): Modifiers = at(readNat(), readModifiers) + protected def readTreeRef(): Tree = at(readNat(), readTree) + + protected def readTypeNameRef(): TypeName = mkTypeName(readNameRef()) + protected def readTermNameRef(): TermName = mkTermName(readNameRef()) + + protected def readTemplateRef(): Template = + readTreeRef() match { + case templ:Template => templ + case other => + errorBadSignature("expected a template (" + other + ")") + } + protected def readCaseDefRef(): CaseDef = + readTreeRef() match { + case tree:CaseDef => tree + case other => + errorBadSignature("expected a case def (" + other + ")") + } + protected def readValDefRef(): ValDef = + readTreeRef() match { + case tree:ValDef => tree + case other => + errorBadSignature("expected a ValDef (" + other + ")") + } + protected def readIdentRef(): Ident = + readTreeRef() match { + case tree:Ident => tree + case other => + errorBadSignature("expected an Ident (" + other + ")") + } + protected def readTypeDefRef(): TypeDef = + readTreeRef() match { + case tree:TypeDef => tree + case other => + errorBadSignature("expected an TypeDef (" + other + ")") + } + + protected def errorBadSignature(msg: String) = + throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg) + + protected def errorMissingRequirement(msg: String): Nothing = + if (debug) errorBadSignature(msg) + else throw new IOException("class file needed by "+classRoot.name+" is missing.\n"+msg) + + protected def errorMissingRequirement(name: Name, owner: Symbol): Nothing = + errorMissingRequirement( + "reference " + (if (name.isTypeName) "type " else "value ") + + name.decode + " of " + owner.tpe.widen + " refers to nonexisting symbol.") + + def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type) {} // can't do it; need a compiler for that. + + def newLazyTypeRef(i: Int): LazyType = new LazyTypeRef(i) + def newLazyTypeRefAndAlias(i: Int, j: Int): LazyType = new LazyTypeRefAndAlias(i, j) + + /** A lazy type which when completed returns type at index `i`. */ + private class LazyTypeRef(i: Int) extends LazyType { + private val definedAtRunId = currentRunId + private val p = phase + override def complete(sym: Symbol) : Unit = { + val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType` + if (p != phase) atPhase(p) (sym setInfo tp) + else sym setInfo tp + if (currentRunId != definedAtRunId) sym.setInfo(adaptToNewRunMap(tp)) + } + override def load(sym: Symbol) { complete(sym) } + } + + /** A lazy type which when completed returns type at index `i` and sets alias + * of completed symbol to symbol at index `j`. + */ + private class LazyTypeRefAndAlias(i: Int, j: Int) extends LazyTypeRef(i) { + override def complete(sym: Symbol) { + super.complete(sym) + var alias = at(j, readSymbol) + if (alias.isOverloaded) { + atPhase(picklerPhase) { + alias = alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt)) + } + } + sym.asInstanceOf[TermSymbol].setAlias(alias) + } + } + } +} diff --git a/src/compiler/scala/reflect/common/util/Chars.scala b/src/compiler/scala/reflect/common/util/Chars.scala deleted file mode 100644 index 4175455f1f..0000000000 --- a/src/compiler/scala/reflect/common/util/Chars.scala +++ /dev/null @@ -1,92 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2006-2011 LAMP/EPFL - * @author Martin Odersky - */ -package scala.reflect.common.util - -import annotation.{ tailrec, switch } -import java.lang.{ Character => JCharacter } - -/** Contains constants and classifier methods for characters */ -trait Chars { - // Be very careful touching these. - // Apparently trivial changes to the way you write these constants - // will cause Scanners.scala to go from a nice efficient switch to - // a ghastly nested if statement which will bring the type checker - // to its knees. See ticket #1456 - // Martin: (this should be verified now that the pattern rules have been redesigned). - final val LF = '\u000A' - final val FF = '\u000C' - final val CR = '\u000D' - final val SU = '\u001A' - - /** Convert a character digit to an Int according to given base, - * -1 if no success */ - def digit2int(ch: Char, base: Int): Int = { - if ('0' <= ch && ch <= '9' && ch < '0' + base) - ch - '0' - else if ('A' <= ch && ch < 'A' + base - 10) - ch - 'A' + 10 - else if ('a' <= ch && ch < 'a' + base - 10) - ch - 'a' + 10 - else - -1 - } - - /** Convert a character to a backslash-u escape */ - def char2uescape(c: Char): String = { - var rest = c.toInt - val buf = new StringBuilder - for (i <- 1 to 4) { - buf ++= (rest % 16).toHexString - rest = rest / 16 - } - "\\u" + buf.toString.reverse - } - - /** Is character a line break? */ - @inline def isLineBreakChar(c: Char) = (c: @switch) match { - case LF|FF|CR|SU => true - case _ => false - } - - /** Is character a whitespace character (but not a new line)? */ - def isWhitespace(c: Char) = - c == ' ' || c == '\t' || c == CR - - /** Can character form part of a doc comment variable $xxx? */ - def isVarPart(c: Char) = - '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' - - /** Can character start an alphanumeric Scala identifier? */ - def isIdentifierStart(c: Char): Boolean = - (c == '_') || (c == '$') || Character.isUnicodeIdentifierStart(c) - - /** Can character form part of an alphanumeric Scala identifier? */ - def isIdentifierPart(c: Char) = - (c == '$') || Character.isUnicodeIdentifierPart(c) - - /** Is character a math or other symbol in Unicode? */ - def isSpecial(c: Char) = { - val chtp = Character.getType(c) - chtp == Character.MATH_SYMBOL.toInt || chtp == Character.OTHER_SYMBOL.toInt - } - - private final val otherLetters = Set[Char]('\u0024', '\u005F') // '$' and '_' - private final val letterGroups = { - import JCharacter._ - Set[Byte](LOWERCASE_LETTER, UPPERCASE_LETTER, OTHER_LETTER, TITLECASE_LETTER, LETTER_NUMBER) - } - def isScalaLetter(ch: Char) = letterGroups(JCharacter.getType(ch).toByte) || otherLetters(ch) - - /** Can character form part of a Scala operator name? */ - def isOperatorPart(c : Char) : Boolean = (c: @switch) match { - case '~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | '<' | - '>' | '?' | ':' | '=' | '&' | - '|' | '/' | '\\' => true - case c => isSpecial(c) - } -} - -object Chars extends Chars { } diff --git a/src/compiler/scala/reflect/std/JavaMappings.scala b/src/compiler/scala/reflect/std/JavaMappings.scala new file mode 100644 index 0000000000..606972420d --- /dev/null +++ b/src/compiler/scala/reflect/std/JavaMappings.scala @@ -0,0 +1,62 @@ +package scala.reflect +package std + +import common._ +import collection.mutable.ListBuffer + +trait JavaMappings { self: Mirror => + + import definitions._ + + type TypeParamMap = Map[java.lang.reflect.TypeVariable[_], Symbol] + + private val localDummy = definitions.RootClass.newValue(NoPosition, "<local-dummy>").setFlag(Flags.SYNTHETIC).setInfo(NoType) + + def fromJava(clazz: java.lang.Class[_]): Symbol = clazz match { + case java.lang.Boolean.TYPE => BooleanClass + case java.lang.Character.TYPE => CharClass + case java.lang.Byte.TYPE => ByteClass + case java.lang.Short.TYPE => ShortClass + case java.lang.Integer.TYPE => IntClass + case java.lang.Long.TYPE => LongClass + case java.lang.Float.TYPE => FloatClass + case java.lang.Double.TYPE => DoubleClass + case java.lang.Void.TYPE => UnitClass + case _ => definitions.getClass(clazz.getName) + } + + def fromJavaType(jtpe: java.lang.reflect.Type)(implicit tparMap: TypeParamMap): Type = jtpe match { + case clazz: java.lang.Class[_] => + if (clazz.isArray) arrayType(fromJavaType(clazz.getComponentType)) + else { + val sym = fromJava(clazz) + if (clazz.isLocalClass) typeRef(NoPrefix, sym, List()) + else if (clazz.isMemberClass) typeRef(fromJavaType(clazz.getDeclaringClass), sym, List()) + else sym.tpe + } + case ptpe: java.lang.reflect.ParameterizedType => + val TypeRef(pre0, sym, _) = fromJavaType(ptpe.getRawType) + val jpre = ptpe.getOwnerType + val pre = if (jpre != null) fromJavaType(jpre) else pre0 + val exbuf = new ListBuffer[Symbol] + def fromJavaArgType(jtp: java.lang.reflect.Type) = fromJavaType(jtp) match { + case BoundedWildcardType(bounds) => + val tparam = pre.typeSymbol.newTypeParameter(NoPosition, newTypeName("x$" + exbuf.length)).setInfo(bounds) + exbuf += tparam + tparam.tpe + case tp => tp + } + val args = ptpe.getActualTypeArguments.toList map fromJavaArgType + existentialAbstraction(exbuf.toList, typeRef(pre, sym, args)) + case gtpe: java.lang.reflect.GenericArrayType => + val etpe = fromJavaType(gtpe.getGenericComponentType) + arrayType(etpe) + case wtpe: java.lang.reflect.WildcardType => + BoundedWildcardType( + TypeBounds( + (wtpe.getLowerBounds map fromJavaType).headOption getOrElse NothingClass.tpe, + intersectionType((wtpe.getUpperBounds map fromJavaType).toList))) + case vtpe: java.lang.reflect.TypeVariable[_] => + tparMap(vtpe).tpe + } +}
\ No newline at end of file diff --git a/src/compiler/scala/reflect/std/Mirror.scala b/src/compiler/scala/reflect/std/Mirror.scala new file mode 100644 index 0000000000..69ddfa1e71 --- /dev/null +++ b/src/compiler/scala/reflect/std/Mirror.scala @@ -0,0 +1,14 @@ +package scala.reflect +package std + +import common._ + +abstract class Mirror extends SymbolTable + with JavaMappings + with SymbolCompleters + with Positions { self => + + val unpickler = new common.pickling.UnPickler { val global: self.type = self } + override val settings = new ReflectSettings + +} diff --git a/src/compiler/scala/reflect/std/Positions.scala b/src/compiler/scala/reflect/std/Positions.scala new file mode 100644 index 0000000000..a6ce52f7c6 --- /dev/null +++ b/src/compiler/scala/reflect/std/Positions.scala @@ -0,0 +1,13 @@ +package scala.reflect +package std + +trait Positions { + + class Position { + def focus: Position = this + def isRange: Boolean = false + def show: String = toString + } + + val NoPosition: Position = new Position +} diff --git a/src/compiler/scala/reflect/std/ReflectSettings.scala b/src/compiler/scala/reflect/std/ReflectSettings.scala new file mode 100644 index 0000000000..a520e1fb89 --- /dev/null +++ b/src/compiler/scala/reflect/std/ReflectSettings.scala @@ -0,0 +1,23 @@ +package scala.reflect +package std + +class ReflectSettings extends common.settings.MutableSettings { + + def newSetting[TT](init: TT) = new SettingValue { + type T = TT + def postSetHook() {} + var v = init + override def isDefault = v == init + } + + val debug = newSetting(false) + val YdepMethTpes = newSetting(false) + val Ynotnull = newSetting(false) + val explaintypes = newSetting(false) + val verbose = newSetting(false) + val uniqid = newSetting(false) + val Xprintpos = newSetting(false) + val printtypes = newSetting(false) + val Yrecursion = newSetting(0) + val maxClassfileName = newSetting(255) +}
\ No newline at end of file diff --git a/src/compiler/scala/reflect/std/SymbolCompleters.scala b/src/compiler/scala/reflect/std/SymbolCompleters.scala new file mode 100644 index 0000000000..678caf500a --- /dev/null +++ b/src/compiler/scala/reflect/std/SymbolCompleters.scala @@ -0,0 +1,80 @@ +package scala.reflect +package std + +import java.io.File +import common._ + +trait SymbolCompleters { self: Mirror => + + class PackageCompleter(owner: Symbol) extends LazyType { + override def isComplete = true + override def complete(sym: Symbol) {} + + private val knownMembers = new Scope + + override def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = { + if (name == nme.ANYNAME) abort("cannot enumerate members of a package") + else { + val sym = knownMembers.lookup(name) + if (sym != NoSymbol) sym + else { + def prepare(sym: Symbol, tpe: Type): Symbol = { + knownMembers.enter(sym) + sym.setInfo(tpe) + } + try { + val prefix = if (owner.isRoot) "" else owner.fullName + "." + val jclazz = java.lang.Class.forName(prefix + name) + val classRoot = owner.newClass(NoPosition, name.toTypeName) + val moduleRoot = owner.newModule(NoPosition, name.toTermName) + val loader = new ClassCompleter(classRoot, moduleRoot, jclazz) + prepare(classRoot, loader) + prepare(moduleRoot, loader) + if (name.isTypeName) classRoot else moduleRoot + } catch { + case ex: ClassNotFoundException => + if (name.isTermName) { + // looking for module, construct package symbol instead + val pkg = owner.newPackage(NoPosition, name) + prepare(pkg, new PackageCompleter(pkg)) + } else + NoSymbol + } + } + } + } + } + + class ClassCompleter(classRoot: Symbol, moduleRoot: Symbol, jclazz: java.lang.Class[_]) extends LazyType { + + import definitions._ + + def scalaSigAttr(jclazz: java.lang.Class[_]): Option[Array[Byte]] = + jclazz.getAnnotation(classOf[ScalaSignature]) match { + case sig: ScalaSignature => Some(sig.bytes.getBytes()) + case _ => jclazz.getAnnotation(classOf[ScalaLongSignature]) match { + case sig: ScalaLongSignature => Some(sig.bytes flatMap (_.getBytes)) + case _ => None + } + } + + def readJava(classRoot: Symbol, moduleRoot: Symbol) { + } + + var _isComplete = false + override def isComplete = _isComplete + + override def complete(sym: Symbol) { + _isComplete = true + scalaSigAttr(jclazz) match { + case Some(bytes) => + val filename = classRoot.fullName.replace('.', File.separatorChar) + unpickler.unpickle(bytes, 0, classRoot, moduleRoot, filename) + case None => + readJava(classRoot, moduleRoot) + } + } + } + + val rootLoader = new PackageCompleter(definitions.RootClass) +}
\ No newline at end of file diff --git a/src/compiler/scala/tools/cmd/program/Tokens.scala b/src/compiler/scala/tools/cmd/program/Tokens.scala index be5e9e411a..c62f17cc35 100644 --- a/src/compiler/scala/tools/cmd/program/Tokens.scala +++ b/src/compiler/scala/tools/cmd/program/Tokens.scala @@ -8,7 +8,7 @@ package cmd package program import nsc._ -import util.Chars.char2uescape +import scala.reflect.Chars.char2uescape import io._ import ast.parser.Tokens._ diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 3338d1433d..98ac0ebd68 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -13,7 +13,7 @@ trait CompilationUnits { self: Global => /** One unit of compilation that has been submitted to the compiler. * It typically corresponds to a single file of source code. It includes * error-reporting hooks. */ - class CompilationUnit(val source: SourceFile) extends CompilationUnitTrait { + class CompilationUnit(val source: SourceFile) { /** the fresh name creator */ var fresh: FreshNameCreator = new FreshNameCreator.Default diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index 866975b414..e72bc705c1 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -145,7 +145,7 @@ class StandardCompileServer extends SocketServer { else { if (isCompilerReusable) { info("[Reusing existing Global instance.]") - compiler.settings = newSettings + compiler.currentSettings = newSettings compiler.reporter = reporter } else { diff --git a/src/compiler/scala/tools/nsc/FatalError.scala b/src/compiler/scala/tools/nsc/FatalError.scala index a18c98f7d4..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/FatalError.scala +++ b/src/compiler/scala/tools/nsc/FatalError.scala @@ -1,19 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc - -import scala.util.control.ControlThrowable - -case class FatalError(msg: String) extends Throwable(msg) - -class MissingRequirementError(val req: String) extends FatalError(req + " not found.") - -object MissingRequirementError { - def unapply(x: Throwable) = x match { - case x: MissingRequirementError => Some(x.req) - case _ => None - } -} diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 6af7fe991f..98937b8d83 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -13,8 +13,8 @@ import scala.tools.util.Profiling import scala.collection.{ mutable, immutable } import io.{ SourceReader, AbstractFile, Path } import reporters.{ Reporter, ConsoleReporter } -import util.{ Exceptional, ClassPath, SourceFile, Statistics, BatchSourceFile, ScriptSourceFile, ShowPickled, returning } -import reflect.generic.{ PickleBuffer, PickleFormat } +import util.{ Exceptional, ClassPath, SourceFile, Statistics, StatisticsInfo, BatchSourceFile, ScriptSourceFile, ShowPickled, returning } +import scala.reflect.common.pickling.{ PickleBuffer, PickleFormat } import settings.{ AestheticSettings } import symtab.{ Flags, SymbolTable, SymbolLoaders, SymbolTrackers } @@ -32,11 +32,17 @@ import backend.jvm.GenJVM import backend.opt.{ Inliners, ClosureElimination, DeadCodeElimination } import backend.icode.analysis._ -class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable - with CompilationUnits - with Plugins - with PhaseAssembly -{ +class Global(var currentSettings: Settings, var reporter: Reporter) extends SymbolTable + with CompilationUnits + with Plugins + with PhaseAssembly + with Trees + with TreePrinters + with DocComments + with symtab.Positions { + + override def settings = currentSettings + // alternate constructors ------------------------------------------ def this(reporter: Reporter) = @@ -45,6 +51,15 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable def this(settings: Settings) = this(settings, new ConsoleReporter(settings)) + // fulfilling requirements + + type AbstractFile = scala.tools.nsc.io.AbstractFile + val AbstractFile = scala.tools.nsc.io.AbstractFile + + def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = gen.mkAttributedQualifier(tpe, termSym) + + def picklerPhase: Phase = currentRun.picklerPhase + // platform specific elements type ThisPlatform = Platform[_] { val global: Global.this.type } @@ -103,7 +118,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable /** Some statistics (normally disabled) set with -Ystatistics */ object statistics extends { val global: Global.this.type = Global.this - } with Statistics + } with StatisticsInfo /** Print tree in detailed form */ object nodePrinters extends { @@ -602,7 +617,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable /* The set of phase objects that is the basis for the compiler phase chain */ protected lazy val phasesSet = new mutable.HashSet[SubComponent] protected lazy val phasesDescMap = new mutable.HashMap[SubComponent, String] withDefaultValue "" - private lazy val phaseTimings = new Phase.TimingModel // tracking phase stats + private lazy val phaseTimings = new Phases.TimingModel // tracking phase stats protected def addToPhasesSet(sub: SubComponent, descr: String) { phasesSet += sub phasesDescMap(sub) = descr @@ -1221,7 +1236,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable // to false except in old code. The downside is that this leaves us calling a // deprecated method: but I see no simple way out, so I leave it for now. def forJVM = opt.jvm - def forMSIL = opt.msil + override def forMSIL = opt.msil def forInteractive = onlyPresentation def forScaladoc = onlyPresentation def createJavadoc = false diff --git a/src/compiler/scala/tools/nsc/NoPhase.scala b/src/compiler/scala/tools/nsc/NoPhase.scala index a74d14acf7..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/NoPhase.scala +++ b/src/compiler/scala/tools/nsc/NoPhase.scala @@ -1,11 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2007-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc - -object NoPhase extends Phase(null) { - def name = "<no phase>" - def run() { throw new Error("NoPhase.run") } -} diff --git a/src/compiler/scala/tools/nsc/Phase.scala b/src/compiler/scala/tools/nsc/Phase.scala index f79b7c4367..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/Phase.scala +++ b/src/compiler/scala/tools/nsc/Phase.scala @@ -1,85 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc - -import symtab.Flags -import util.TableDef - -abstract class Phase(val prev: Phase) { - - type Id = Int - - val id: Id = if (prev eq null) 0 else prev.id + 1 - - /** New flags visible after this phase has completed */ - def nextFlags: Long = 0l - - /** New flags visible once this phase has started */ - def newFlags: Long = 0l - - private var fmask: Long = - if (prev eq null) Flags.InitialFlags else prev.flagMask | prev.nextFlags | newFlags - def flagMask: Long = fmask - - private var nx: Phase = this - if ((prev ne null) && (prev ne NoPhase)) prev.nx = this - - def next: Phase = nx - - def name: String - def description: String = name - // Will running with -Ycheck:name work? - def checkable: Boolean = true - // def devirtualized: Boolean = false - def specialized: Boolean = false - def erasedTypes: Boolean = false - def flatClasses: Boolean = false - def refChecked: Boolean = false - def keepsTypeParams = true - def run(): Unit - - override def toString() = name - override def hashCode = id.## + name.## - override def equals(other: Any) = other match { - case x: Phase => id == x.id && name == x.name - case _ => false - } -} - -object Phase { - val MaxPhases = 64 - - /** A class for tracking something about each phase. - */ - class Model[T: Manifest] { - case class Cell(ph: Phase, value: T) { - def name = ph.name - def id = ph.id - } - val values = new Array[Cell](MaxPhases + 1) - def results = values filterNot (_ == null) - def apply(ph: Phase): T = values(ph.id).value - def update(ph: Phase, value: T): Unit = values(ph.id) = Cell(ph, value) - } - /** A class for recording the elapsed time of each phase in the - * interests of generating a classy and informative table. - */ - class TimingModel extends Model[Long] { - var total: Long = 0 - def table() = { - total = results map (_.value) sum; - new Format.Table(results sortBy (-_.value)) - } - object Format extends TableDef[Cell] { - >> ("phase" -> (_.name)) >+ " " - << ("id" -> (_.id)) >+ " " - >> ("ms" -> (_.value)) >+ " " - << ("share" -> (_.value.toDouble * 100 / total formatted "%.2f")) - } - def formatted = "" + table() - } -} - diff --git a/src/compiler/scala/tools/nsc/ast/DocComments.scala b/src/compiler/scala/tools/nsc/ast/DocComments.scala index be729904db..91d8f9fb87 100755 --- a/src/compiler/scala/tools/nsc/ast/DocComments.scala +++ b/src/compiler/scala/tools/nsc/ast/DocComments.scala @@ -17,7 +17,7 @@ import scala.collection.mutable.{HashMap, ListBuffer, StringBuilder} * @author Martin Odersky * @version 1.0 */ -trait DocComments { self: SymbolTable => +trait DocComments { self: Global => def reporter: Reporter diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index af2ebc4251..29dc2c62d5 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -13,199 +13,12 @@ import symtab.SymbolTable /** XXX to resolve: TreeGen only assumes global is a SymbolTable, but * TreeDSL at the moment expects a Global. Can we get by with SymbolTable? */ -abstract class TreeGen { - val global: SymbolTable +abstract class TreeGen extends reflect.common.TreeGen { + val global: Global import global._ import definitions._ - def rootId(name: Name) = Select(Ident(nme.ROOTPKG), name) - def rootScalaDot(name: Name) = Select(rootId(nme.scala_) setSymbol ScalaPackage, name) - def scalaDot(name: Name) = Select(Ident(nme.scala_) setSymbol ScalaPackage, name) - def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) - def scalaUnitConstr = scalaDot(tpnme.Unit) - def scalaScalaObjectConstr = scalaDot(tpnme.ScalaObject) - def productConstr = scalaDot(tpnme.Product) - def serializableConstr = scalaDot(tpnme.Serializable) - - def scalaFunctionConstr(argtpes: List[Tree], restpe: Tree, abstractFun: Boolean = false): Tree = { - val cls = if (abstractFun) - mkAttributedRef(AbstractFunctionClass(argtpes.length)) - else - mkAttributedRef(FunctionClass(argtpes.length)) - AppliedTypeTree(cls, argtpes :+ restpe) - } - - /** Builds a reference to value whose type is given stable prefix. - * The type must be suitable for this. For example, it - * must not be a TypeRef pointing to an abstract type variable. - */ - def mkAttributedQualifier(tpe: Type): Tree = - mkAttributedQualifier(tpe, NoSymbol) - - /** Builds a reference to value whose type is given stable prefix. - * If the type is unsuitable, e.g. it is a TypeRef for an - * abstract type variable, then an Ident will be made using - * termSym as the Ident's symbol. In that case, termSym must - * not be NoSymbol. - */ - def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = tpe match { - case NoPrefix => - EmptyTree - case ThisType(clazz) => - if (clazz.isEffectiveRoot) EmptyTree - else mkAttributedThis(clazz) - case SingleType(pre, sym) => - applyIfNoArgs(mkAttributedStableRef(pre, sym)) - case TypeRef(pre, sym, args) => - if (sym.isRoot) { - mkAttributedThis(sym) - } else if (sym.isModuleClass) { - applyIfNoArgs(mkAttributedRef(pre, sym.sourceModule)) - } else if (sym.isModule || sym.isClass) { - assert(phase.erasedTypes, tpe) - mkAttributedThis(sym) - } else if (sym.isType) { - assert(termSym != NoSymbol, tpe) - mkAttributedIdent(termSym) setType tpe - } else { - mkAttributedRef(pre, sym) - } - - case ConstantType(value) => - Literal(value) setType tpe - - case AnnotatedType(_, atp, _) => - mkAttributedQualifier(atp) - - case RefinedType(parents, _) => - // I am unclear whether this is reachable, but - // the following implementation looks logical -Lex - val firstStable = parents.find(_.isStable) - assert(!firstStable.isEmpty, tpe) - mkAttributedQualifier(firstStable.get) - - case _ => - abort("bad qualifier: " + tpe) - } - /** If this is a reference to a method with an empty - * parameter list, wrap it in an apply. - */ - private def applyIfNoArgs(qual: Tree) = qual.tpe match { - case MethodType(Nil, restpe) => Apply(qual, Nil) setType restpe - case _ => qual - } - - /** Builds a reference to given symbol with given stable prefix. */ - def mkAttributedRef(pre: Type, sym: Symbol): Tree = { - val qual = mkAttributedQualifier(pre) - qual match { - case EmptyTree => mkAttributedIdent(sym) - case This(clazz) if qual.symbol.isEffectiveRoot => mkAttributedIdent(sym) - case _ => mkAttributedSelect(qual, sym) - } - } - - /** Builds a reference to given symbol. */ - def mkAttributedRef(sym: Symbol): Tree = - if (sym.owner.isClass) mkAttributedRef(sym.owner.thisType, sym) - else mkAttributedIdent(sym) - - /** Builds an untyped reference to given symbol. */ - def mkUnattributedRef(sym: Symbol): Tree = - if (sym.owner.isClass) Select(This(sym.owner), sym) - else Ident(sym) - - /** Replaces tree type with a stable type if possible */ - def stabilize(tree: Tree): Tree = { - for(tp <- stableTypeFor(tree)) tree.tpe = tp - tree - } - - /** Computes stable type for a tree if possible */ - def stableTypeFor(tree: Tree): Option[Type] = tree match { - case Ident(_) if tree.symbol.isStable => - Some(singleType(tree.symbol.owner.thisType, tree.symbol)) - case Select(qual, _) if ((tree.symbol ne null) && (qual.tpe ne null)) && // turned assert into guard for #4064 - tree.symbol.isStable && qual.tpe.isStable => - Some(singleType(qual.tpe, tree.symbol)) - case _ => - None - } - - /** Cast `tree' to type `pt' */ - def mkCast(tree: Tree, pt: Type): Tree = { - if (settings.debug.value) log("casting " + tree + ":" + tree.tpe + " to " + pt) - assert(!tree.tpe.isInstanceOf[MethodType], tree) - assert(!pt.typeSymbol.isPackageClass) - assert(!pt.typeSymbol.isPackageObjectClass) - assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize)) //@MAT only called during erasure, which already takes care of that - atPos(tree.pos)(mkAsInstanceOf(tree, pt, false)) - } - - /** Builds a reference with stable type to given symbol */ - def mkAttributedStableRef(pre: Type, sym: Symbol): Tree = - stabilize(mkAttributedRef(pre, sym)) - - def mkAttributedStableRef(sym: Symbol): Tree = - stabilize(mkAttributedRef(sym)) - - def mkAttributedThis(sym: Symbol): Tree = - This(sym.name.toTypeName) setSymbol sym setType sym.thisType - - def mkAttributedIdent(sym: Symbol): Tree = - Ident(sym.name) setSymbol sym setType sym.tpe - - def mkAttributedSelect(qual: Tree, sym: Symbol): Tree = { - // Tests involving the repl fail without the .isEmptyPackage condition. - if (qual.symbol != null && (qual.symbol.isEffectiveRoot || qual.symbol.isEmptyPackage)) - mkAttributedIdent(sym) - else { - val pkgQualifier = - if (sym != null && sym.owner.isPackageObjectClass && sym.owner.owner == qual.tpe.typeSymbol) { - val obj = sym.owner.sourceModule - Select(qual, nme.PACKAGEkw) setSymbol obj setType singleType(qual.tpe, obj) - } - else qual - - val tree = Select(pkgQualifier, sym) - if (pkgQualifier.tpe == null) tree - else tree setType (qual.tpe memberType sym) - } - } - - private def mkTypeApply(value: Tree, tpe: Type, what: Symbol) = - Apply( - TypeApply( - mkAttributedSelect(value, what), - List(TypeTree(tpe.normalize)) - ), - Nil - ) - /** Builds an instance test with given value and type. */ - def mkIsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree = - mkTypeApply(value, tpe, (if (any) Any_isInstanceOf else Object_isInstanceOf)) - - /** Builds a cast with given value and type. */ - def mkAsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree = - mkTypeApply(value, tpe, (if (any) Any_asInstanceOf else Object_asInstanceOf)) - - /** Cast `tree' to 'pt', unless tpe is a subtype of pt, or pt is Unit. */ - def maybeMkAsInstanceOf(tree: Tree, pt: Type, tpe: Type, beforeRefChecks: Boolean = false): Tree = - if ((pt == UnitClass.tpe) || (tpe <:< pt)) { - log("no need to cast from " + tpe + " to " + pt) - tree - } else - atPos(tree.pos) { - if (beforeRefChecks) - TypeApply(mkAttributedSelect(tree, Any_asInstanceOf), List(TypeTree(pt))) - else - mkAsInstanceOf(tree, pt) - } - - def mkClassOf(tp: Type): Tree = - Literal(Constant(tp)) setType ConstantType(Constant(tp))// ClassType(tp) - def mkCheckInit(tree: Tree): Tree = { val tpe = if (tree.tpe != null || !tree.hasSymbol) tree.tpe @@ -218,44 +31,6 @@ abstract class TreeGen { tree } - /** Builds a list with given head and tail. */ - def mkNewCons(head: Tree, tail: Tree): Tree = - New(Apply(mkAttributedRef(ConsClass), List(head, tail))) - - /** Builds a list with given head and tail. */ - def mkNil: Tree = mkAttributedRef(NilModule) - - /** Builds a tree representing an undefined local, as in - * var x: T = _ - * which is appropriate to the given Type. - */ - def mkZero(tp: Type): Tree = { - val sym = tp.typeSymbol - val tree = - if (sym == UnitClass) Literal(()) - else if (sym == BooleanClass) Literal(false) - else if (isValueClass(sym)) Literal(0) - else if (NullClass.tpe <:< tp) Literal(null: Any) - else abort("Cannot determine zero for " + tp) - - tree setType tp - } - - /** Builds a tuple */ - def mkTuple(elems: List[Tree]): Tree = - if (elems.isEmpty) Literal(()) - else Apply( - Select(mkAttributedRef(TupleClass(elems.length).caseModule), nme.apply), - elems) - - // tree1 AND tree2 - def mkAnd(tree1: Tree, tree2: Tree): Tree = - Apply(Select(tree1, Boolean_and), List(tree2)) - - // tree1 OR tree2 - def mkOr(tree1: Tree, tree2: Tree): Tree = - Apply(Select(tree1, Boolean_or), List(tree2)) - // wrap the given expression in a SoftReference so it can be gc-ed def mkSoftRef(expr: Tree): Tree = New(TypeTree(SoftReferenceClass.tpe), List(List(expr))) diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index 96f4355590..8c22f750b6 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -10,418 +10,13 @@ import java.io.{ OutputStream, PrintWriter, StringWriter, Writer } import symtab.Flags._ import symtab.SymbolTable -trait TreePrinters { trees: SymbolTable => +trait TreePrinters extends reflect.common.TreePrinters { this: Global => import treeInfo.{ IsTrue, IsFalse } - final val showOuterTests = false + class TreePrinter(out: PrintWriter) extends super.TreePrinter(out) { - /** Adds backticks if the name is a scala keyword. */ - def quotedName(name: Name, decode: Boolean): String = { - val s = if (decode) name.decode else name.toString - val term = name.toTermName - if (nme.keywords(term) && term != nme.USCOREkw) "`%s`" format s - else s - } - def quotedName(name: Name): String = quotedName(name, false) - - /** Turns a path into a String, introducing backquotes - * as necessary. - */ - def backquotedPath(t: Tree): String = t match { - case Select(qual, name) => "%s.%s".format(backquotedPath(qual), quotedName(name)) - case Ident(name) => quotedName(name) - case _ => t.toString - } - - class TreePrinter(out: PrintWriter) extends trees.AbsTreePrinter(out) { - protected var indentMargin = 0 - protected val indentStep = 2 - protected var indentString = " " // 40 - - def flush() = out.flush() - - def indent() = indentMargin += indentStep - def undent() = indentMargin -= indentStep - - protected def doPrintPositions = settings.Xprintpos.value - def printPosition(tree: Tree) = if (doPrintPositions) print(tree.pos.show) - - def println() { - out.println() - while (indentMargin > indentString.length()) - indentString += indentString - if (indentMargin > 0) - out.write(indentString, 0, indentMargin) - } - - def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) { - ls match { - case List() => - case List(x) => printelem(x) - case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep) - } - } - - def printColumn(ts: List[Tree], start: String, sep: String, end: String) { - print(start); indent; println() - printSeq(ts){print}{print(sep); println()}; undent; println(); print(end) - } - - def printRow(ts: List[Tree], start: String, sep: String, end: String) { - print(start); printSeq(ts){print}{print(sep)}; print(end) - } - - def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") } - - def printTypeParams(ts: List[TypeDef]) { - if (!ts.isEmpty) { - print("["); printSeq(ts){ t => - printAnnotations(t) - printParam(t) - }{print(", ")}; print("]") - } - } - - def printValueParams(ts: List[ValDef]) { - print("(") - if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "") - printSeq(ts){printParam}{print(", ")} - print(")") - } - - def printParam(tree: Tree) { - tree match { - case ValDef(mods, name, tp, rhs) => - printPosition(tree) - printAnnotations(tree) - print(symName(tree, name)); printOpt(": ", tp); printOpt(" = ", rhs) - case TypeDef(mods, name, tparams, rhs) => - printPosition(tree) - print(symName(tree, name)) - printTypeParams(tparams); print(rhs) - } - } - - def printBlock(tree: Tree) { - tree match { - case Block(_, _) => - print(tree) - case _ => - printColumn(List(tree), "{", ";", "}") - } - } - - private def symFn[T](tree: Tree, f: Symbol => T, orElse: => T): T = tree.symbol match { - case null | NoSymbol => orElse - case sym => f(sym) - } - private def ifSym(tree: Tree, p: Symbol => Boolean) = symFn(tree, p, false) - - private def symNameInternal(tree: Tree, name: Name, decoded: Boolean): String = { - def nameFn(sym: Symbol) = { - val prefix = if (sym.isMixinConstructor) "/*%s*/".format(quotedName(sym.owner.name, decoded)) else "" - prefix + tree.symbol.nameString - } - symFn(tree, nameFn, quotedName(name, decoded)) - } - - def decodedSymName(tree: Tree, name: Name) = symNameInternal(tree, name, true) - def symName(tree: Tree, name: Name) = symNameInternal(tree, name, false) - - def printOpt(prefix: String, tree: Tree) { - if (!tree.isEmpty) { print(prefix); print(tree) } - } - - def printModifiers(tree: Tree, mods: Modifiers): Unit = printFlags( - if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + ( - if (tree.symbol == NoSymbol) mods.privateWithin - else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name - else "" - ) - ) - - def printFlags(flags: Long, privateWithin: String) { - var mask: Long = if (settings.debug.value) -1L else PrintableFlags - val s = flagsToString(flags & mask, privateWithin) - if (s != "") print(s + " ") - } - - def printAnnotations(tree: Tree) { - val annots = - if (tree.symbol.hasAssignedAnnotations) tree.symbol.annotations - else tree.asInstanceOf[MemberDef].mods.annotations - - annots foreach (annot => print("@"+annot+" ")) - } - - def print(str: String) { out.print(str) } - def print(name: Name) { print(quotedName(name)) } - - private var currentOwner: Symbol = NoSymbol - private var selectorType: Type = NoType - - def printRaw(tree: Tree) { - tree match { - case EmptyTree => - print("<empty>") - - case ClassDef(mods, name, tparams, impl) => - printAnnotations(tree) - printModifiers(tree, mods) - val word = - if (mods.hasTraitFlag) "trait" - else if (ifSym(tree, _.isModuleClass)) "object" - else "class" - - print(word + " " + symName(tree, name)) - printTypeParams(tparams) - print(if (mods.isDeferred) " <: " else " extends "); print(impl) - - case PackageDef(packaged, stats) => - printAnnotations(tree) - print("package "); print(packaged); printColumn(stats, " {", ";", "}") - - case ModuleDef(mods, name, impl) => - printAnnotations(tree) - printModifiers(tree, mods); print("object " + symName(tree, name)) - print(" extends "); print(impl) - - case ValDef(mods, name, tp, rhs) => - printAnnotations(tree) - printModifiers(tree, mods) - print(if (mods.isMutable) "var " else "val ") - print(symName(tree, name)) - printOpt(": ", tp) - if (!mods.isDeferred) { - print(" = ") - if (rhs.isEmpty) print("_") else print(rhs) - } - - case DefDef(mods, name, tparams, vparamss, tp, rhs) => - printAnnotations(tree) - printModifiers(tree, mods) - print("def " + symName(tree, name)) - printTypeParams(tparams); vparamss foreach printValueParams - printOpt(": ", tp); printOpt(" = ", rhs) - - case TypeDef(mods, name, tparams, rhs) => - if (mods hasFlag (PARAM | DEFERRED)) { - printAnnotations(tree) - printModifiers(tree, mods); print("type "); printParam(tree) - } else { - printAnnotations(tree) - printModifiers(tree, mods); print("type " + symName(tree, name)) - printTypeParams(tparams); printOpt(" = ", rhs) - } - - case LabelDef(name, params, rhs) => - print(symName(tree, name)); printRow(params, "(", ",", ")"); printBlock(rhs) - - case Import(expr, selectors) => - // Is this selector remapping a name (i.e, {name1 => name2}) - def isNotRemap(s: ImportSelector) : Boolean = (s.name == nme.WILDCARD || s.name == s.rename) - def selectorToString(s: ImportSelector): String = { - val from = quotedName(s.name) - if (isNotRemap(s)) from - else from + "=>" + quotedName(s.rename) - } - print("import "); print(backquotedPath(expr)) - print(".") - selectors match { - case List(s) => - // If there is just one selector and it is not remapping a name, no braces are needed - if (isNotRemap(s)) { - print(selectorToString(s)) - } else { - print("{"); print(selectorToString(s)); print("}") - } - // If there is more than one selector braces are always needed - case many => - print(many.map(selectorToString).mkString("{", ", ", "}")) - } - - case DocDef(comment, definition) => - print(comment.raw); println(); print(definition) - - case Template(parents, self, body) => - val currentOwner1 = currentOwner - if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner - printRow(parents, " with ") - if (!body.isEmpty) { - if (self.name != nme.WILDCARD) { - print(" { "); print(self.name); printOpt(": ", self.tpt); print(" => ") - } else if (!self.tpt.isEmpty) { - print(" { _ : "); print(self.tpt); print(" => ") - } else { - print(" {") - } - printColumn(body, "", ";", "}") - } - currentOwner = currentOwner1 - - case Block(stats, expr) => - printColumn(stats ::: List(expr), "{", ";", "}") - - case Match(selector, cases) => - val selectorType1 = selectorType - selectorType = selector.tpe - print(selector); printColumn(cases, " match {", "", "}") - selectorType = selectorType1 - - case CaseDef(pat, guard, body) => - print("case ") - def patConstr(pat: Tree): Tree = pat match { - case Apply(fn, args) => patConstr(fn) - case _ => pat - } - if (showOuterTests && - needsOuterTest( - patConstr(pat).tpe.finalResultType, selectorType, currentOwner)) - print("???") - print(pat); printOpt(" if ", guard) - print(" => "); print(body) - - case Alternative(trees) => - printRow(trees, "(", "| ", ")") - - case Star(elem) => - print("("); print(elem); print(")*") - - case Bind(name, t) => - print("("); print(symName(tree, name)); print(" @ "); print(t); print(")") - - case UnApply(fun, args) => - print(fun); print(" <unapply> "); printRow(args, "(", ", ", ")") - - case ArrayValue(elemtpt, trees) => - print("Array["); print(elemtpt); printRow(trees, "]{", ", ", "}") - - case Function(vparams, body) => - print("("); printValueParams(vparams); print(" => "); print(body); print(")") - if (settings.uniqid.value && tree.symbol != null) print("#"+tree.symbol.id) - - case Assign(lhs, rhs) => - print(lhs); print(" = "); print(rhs) - - case AssignOrNamedArg(lhs, rhs) => - print(lhs); print(" = "); print(rhs) - - case If(cond, thenp, elsep) => - print("if ("); print(cond); print(")"); indent; println() - print(thenp); undent - if (!elsep.isEmpty) { - println(); print("else"); indent; println(); print(elsep); undent - } - - case Return(expr) => - print("return "); print(expr) - - case Try(block, catches, finalizer) => - print("try "); printBlock(block) - if (!catches.isEmpty) printColumn(catches, " catch {", "", "}") - printOpt(" finally ", finalizer) - - case Throw(expr) => - print("throw "); print(expr) - - case New(tpe) => - print("new "); print(tpe) - - case Typed(expr, tp) => - print("("); print(expr); print(": "); print(tp); print(")") - - case TypeApply(fun, targs) => - print(fun); printRow(targs, "[", ", ", "]") - - case Apply(fun, vargs) => - print(fun); printRow(vargs, "(", ", ", ")") - - case ApplyDynamic(qual, vargs) => - print("<apply-dynamic>("); print(qual); print("#"); print(tree.symbol.nameString) - printRow(vargs, ", (", ", ", "))") - - case Super(This(qual), mix) => - if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".") - print("super") - if (!mix.isEmpty) - print("[" + mix + "]") - - case Super(qual, mix) => - print(qual) - print(".super") - if (!mix.isEmpty) - print("[" + mix + "]") - - case This(qual) => - if (!qual.isEmpty) print(symName(tree, qual) + ".") - print("this") - - case Select(qual @ New(tpe), name) if (!settings.debug.value) => - print(qual) - - case Select(qualifier, name) => - print(backquotedPath(qualifier)); print("."); print(symName(tree, name)) - - case Ident(name) => - print(symName(tree, name)) - - case Literal(x) => - print(x.escapedStringValue) - - case tt: TypeTree => - if ((tree.tpe eq null) || (settings.Xprintpos.value && tt.original != null)) { - if (tt.original != null) { print("<type: "); print(tt.original); print(">") } - else print("<type ?>") - } else if ((tree.tpe.typeSymbol ne null) && tree.tpe.typeSymbol.isAnonymousClass) { - print(tree.tpe.typeSymbol.toString()) - } else { - print(tree.tpe.toString()) - } - - case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) => - def printAnnot() { - print("@"); print(tpt) - if (!args.isEmpty) - printRow(args, "(", ",", ")") - } - if (tree.isType) { print(tree); print(" "); printAnnot() } - else { print(tree); print(": "); printAnnot() } - - case SingletonTypeTree(ref) => - print(ref); print(".type") - - case SelectFromTypeTree(qualifier, selector) => - print(qualifier); print("#"); print(symName(tree, selector)) - - case CompoundTypeTree(templ) => - print(templ) - - case AppliedTypeTree(tp, args) => - print(tp); printRow(args, "[", ", ", "]") - - case TypeBoundsTree(lo, hi) => - printOpt(" >: ", lo); printOpt(" <: ", hi) - - case ExistentialTypeTree(tpt, whereClauses) => - print(tpt); - printColumn(whereClauses, " forSome { ", ";", "}") - - case SelectFromArray(qualifier, name, _) => - print(qualifier); print(".<arr>"); print(symName(tree, name)) - - case TypeTreeWithDeferredRefCheck() => - print("<tree with deferred refcheck>") - - case tree => - print("<unknown tree of class "+tree.getClass+">") - } - if (settings.printtypes.value && tree.isTerm && !tree.isEmpty) { - print("{"); print(if (tree.tpe eq null) "<null>" else tree.tpe.toString()); print("}") - } - } - - def print(tree: Tree) { + override def print(tree: Tree) { printPosition(tree) printRaw( if (tree.isDef && tree.symbol != NoSymbol && tree.symbol.isInitialized) { @@ -685,24 +280,9 @@ trait TreePrinters { trees: SymbolTable => def newCompactTreePrinter(stream: OutputStream): CompactTreePrinter = newCompactTreePrinter(new PrintWriter(stream)) def newCompactTreePrinter(): CompactTreePrinter = newCompactTreePrinter(new PrintWriter(ConsoleWriter)) - def newTreePrinter(writer: PrintWriter): TreePrinter = + override def newTreePrinter(writer: PrintWriter): TreePrinter = if (settings.Ycompacttrees.value) newCompactTreePrinter(writer) else newStandardTreePrinter(writer) - def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream)) - def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter)) - - /** A writer that writes to the current Console and - * is sensitive to replacement of the Console's - * output stream. - */ - object ConsoleWriter extends Writer { - override def write(str: String) { Console.print(str) } - - def write(cbuf: Array[Char], off: Int, len: Int) { - write(new String(cbuf, off, len)) - } - - def close = { /* do nothing */ } - def flush = { /* do nothing */ } - } + override def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream)) + override def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter)) } diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 0e15979460..bb61534f16 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -6,1155 +6,11 @@ package scala.tools.nsc package ast -import scala.collection.mutable.ListBuffer -import scala.tools.nsc.symtab.SymbolTable -import scala.tools.nsc.symtab.Flags._ -import scala.tools.nsc.util.{ FreshNameCreator, HashSet, SourceFile } - -trait Trees extends reflect.generic.Trees { self: SymbolTable => - - trait CompilationUnitTrait { - var body: Tree - val source: SourceFile - def fresh : FreshNameCreator - def freshTermName(prefix: String): TermName - def freshTypeName(prefix: String): TypeName - } - - type CompilationUnit <: CompilationUnitTrait - - protected def flagsIntoString(flags: Long, privateWithin: String): String = flagsToString(flags, privateWithin) - - // sub-components -------------------------------------------------- +trait Trees extends reflect.common.Trees { self: Global => lazy val treePrinter = newTreePrinter() - object treeInfo extends { - val trees: Trees.this.type = Trees.this - } with TreeInfo - - val treeCopy = new LazyTreeCopier() - - implicit def treeWrapper(tree: Tree): TreeOps = new TreeOps(tree) - - class TreeOps(tree: Tree) { - def isTerm: Boolean = tree match { - case _: TermTree => true - case Bind(name, _) => name.isTermName - case Select(_, name) => name.isTermName - case Ident(name) => name.isTermName - case Annotated(_, arg) => arg.isTerm - case DocDef(_, defn) => defn.isTerm - case _ => false - } - - def isType: Boolean = tree match { - case _: TypTree => true - case Bind(name, _) => name.isTypeName - case Select(_, name) => name.isTypeName - case Ident(name) => name.isTypeName - case Annotated(_, arg) => arg.isType - case DocDef(_, defn) => defn.isType - case _ => false - } - - def isErroneous = (tree.tpe ne null) && tree.tpe.isErroneous - def isTyped = (tree.tpe ne null) && !tree.tpe.isErroneous - - /** Apply `f' to each subtree */ - def foreach(f: Tree => Unit) { new ForeachTreeTraverser(f).traverse(tree) } - - /** If 'pf' is defined for a given subtree, call super.traverse(pf(tree)), - * otherwise super.traverse(tree). - */ - def foreachPartial(pf: PartialFunction[Tree, Tree]) { new ForeachPartialTreeTraverser(pf).traverse(tree) } - - /** Find all subtrees matching predicate `p' */ - def filter(f: Tree => Boolean): List[Tree] = { - val ft = new FilterTreeTraverser(f) - ft.traverse(tree) - ft.hits.toList - } - - /** Returns optionally first tree (in a preorder traversal) which satisfies predicate `p', - * or None if none exists. - */ - def find(p: Tree => Boolean): Option[Tree] = { - val ft = new FindTreeTraverser(p) - ft.traverse(tree) - ft.result - } - - def changeOwner(pairs: (Symbol, Symbol)*): Tree = { - pairs.foldLeft(tree) { case (t, (oldOwner, newOwner)) => - new ChangeOwnerTraverser(oldOwner, newOwner) apply t - } - } - - /** Is there part of this tree which satisfies predicate `p'? */ - def exists(p: Tree => Boolean): Boolean = !find(p).isEmpty - - def equalsStructure(that : Tree) = equalsStructure0(that)(_ eq _) - def equalsStructure0(that: Tree)(f: (Tree,Tree) => Boolean): Boolean = - f(tree, that) || ((tree.productArity == that.productArity) && { - def equals0(this0: Any, that0: Any): Boolean = (this0, that0) match { - case (x: Tree, y: Tree) => f(x, y) || (x equalsStructure0 y)(f) - case (xs: List[_], ys: List[_]) => (xs corresponds ys)(equals0) - case _ => this0 == that0 - } - def compareOriginals() = (tree, that) match { - case (x: TypeTree, y: TypeTree) if x.original != null && y.original != null => - (x.original equalsStructure0 y.original)(f) - case _ => - true - } - - (tree.productIterator zip that.productIterator forall { case (x, y) => equals0(x, y) }) && compareOriginals() - }) - - def shallowDuplicate: Tree = new ShallowDuplicator(tree) transform tree - def shortClass: String = tree.getClass.getName split "[.$]" last - } - - private[scala] override def duplicateTree(tree: Tree): Tree = duplicator transform tree - -// ---- values and creators --------------------------------------- - - /** @param sym the class symbol - * @return the implementation template - */ - def ClassDef(sym: Symbol, impl: Template): ClassDef = - atPos(sym.pos) { - ClassDef(Modifiers(sym.flags), - sym.name.toTypeName, - sym.typeParams map TypeDef, - impl) setSymbol sym - } - - /** Construct class definition with given class symbol, value parameters, - * supercall arguments and template body. - * - * @param sym the class symbol - * @param constrMods the modifiers for the class constructor, i.e. as in `class C private (...)' - * @param vparamss the value parameters -- if they have symbols they - * should be owned by `sym' - * @param argss the supercall arguments - * @param body the template statements without primary constructor - * and value parameter fields. - */ - def ClassDef(sym: Symbol, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree], superPos: Position): ClassDef = - ClassDef(sym, - Template(sym.info.parents map TypeTree, - if (sym.thisSym == sym || phase.erasedTypes) emptyValDef else ValDef(sym.thisSym), - constrMods, vparamss, argss, body, superPos)) - - /** - * @param sym the class symbol - * @param impl the implementation template - */ - def ModuleDef(sym: Symbol, impl: Template): ModuleDef = - atPos(sym.pos) { - ModuleDef(Modifiers(sym.flags), sym.name, impl) setSymbol sym - } - - def ValDef(sym: Symbol, rhs: Tree): ValDef = - atPos(sym.pos) { - ValDef(Modifiers(sym.flags), sym.name, - TypeTree(sym.tpe) setPos sym.pos.focus, - rhs) setSymbol sym - } - - def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree) - - object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) { - override def isEmpty = true - super.setPos(NoPosition) - override def setPos(pos: Position) = { assert(false); this } - } - - def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef = - atPos(sym.pos) { - assert(sym != NoSymbol) - DefDef(Modifiers(sym.flags), - sym.name, - sym.typeParams map TypeDef, - vparamss, - TypeTree(sym.tpe.finalResultType) setPos sym.pos.focus, - rhs) setSymbol sym - } - - def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef = - DefDef(sym, Modifiers(sym.flags), vparamss, rhs) - - def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef = - DefDef(sym, mods, sym.paramss map (_.map(ValDef)), rhs) - - def DefDef(sym: Symbol, rhs: Tree): DefDef = - DefDef(sym, Modifiers(sym.flags), rhs) - - def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = { - DefDef(sym, rhs(sym.info.paramss)) - } - - /** A TypeDef node which defines given `sym' with given tight hand side `rhs'. */ - def TypeDef(sym: Symbol, rhs: Tree): TypeDef = - atPos(sym.pos) { - TypeDef(Modifiers(sym.flags), sym.name.toTypeName, sym.typeParams map TypeDef, rhs) setSymbol sym - } - - /** A TypeDef node which defines abstract type or type parameter for given `sym' */ - def TypeDef(sym: Symbol): TypeDef = - TypeDef(sym, TypeBoundsTree(TypeTree(sym.info.bounds.lo), TypeTree(sym.info.bounds.hi))) - - def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef = - atPos(sym.pos) { - LabelDef(sym.name, params map Ident, rhs) setSymbol sym - } - - /** Generates a template with constructor corresponding to - * - * constrmods (vparams1_) ... (vparams_n) preSuper { presupers } - * extends superclass(args_1) ... (args_n) with mixins { self => body } - * - * This gets translated to - * - * extends superclass with mixins { self => - * presupers' // presupers without rhs - * vparamss // abstract fields corresponding to value parameters - * def <init>(vparamss) { - * presupers - * super.<init>(args) - * } - * body - * } - */ - def Template(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree], superPos: Position): Template = { - /* Add constructor to template */ - - // create parameters for <init> as synthetic trees. - var vparamss1 = - vparamss map (vps => vps.map { vd => - atPos(vd.pos.focus) { - ValDef( - Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM | BYNAMEPARAM) | PARAM | PARAMACCESSOR) withAnnotations vd.mods.annotations, - vd.name, vd.tpt.duplicate, vd.rhs.duplicate) - }}) - val (edefs, rest) = body span treeInfo.isEarlyDef - val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef - val (lvdefs, gvdefs) = evdefs map { - case vdef @ ValDef(mods, name, tpt, rhs) => - val fld = treeCopy.ValDef( - vdef.duplicate, mods, name, - atPos(vdef.pos.focus) { TypeTree() setOriginal tpt setPos tpt.pos.focus }, // atPos in case - EmptyTree) - val local = treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) - (local, fld) - } unzip - - val constrs = { - if (constrMods hasFlag TRAIT) { - if (body forall treeInfo.isInterfaceMember) List() - else List( - atPos(wrappingPos(superPos, lvdefs)) ( - DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, List(), List(List()), TypeTree(), Block(lvdefs, Literal(()))))) - } else { - // convert (implicit ... ) to ()(implicit ... ) if its the only parameter section - if (vparamss1.isEmpty || !vparamss1.head.isEmpty && vparamss1.head.head.mods.isImplicit) - vparamss1 = List() :: vparamss1; - val superRef: Tree = atPos(superPos) { - Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR) - } - val superCall = (superRef /: argss) (Apply) - List( - atPos(wrappingPos(superPos, lvdefs ::: argss.flatten)) ( - DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(()))))) - } - } - // println("typed template, gvdefs = "+gvdefs+", parents = "+parents+", constrs = "+constrs) - constrs foreach (ensureNonOverlapping(_, parents ::: gvdefs)) - // vparamss2 are used as field definitions for the class. remove defaults - val vparamss2 = vparamss map (vps => vps map { vd => - treeCopy.ValDef(vd, vd.mods &~ DEFAULTPARAM, vd.name, vd.tpt, EmptyTree) - }) - Template(parents, self, gvdefs ::: vparamss2.flatten ::: constrs ::: etdefs ::: rest) - } - - /** casedef shorthand */ - def CaseDef(pat: Tree, body: Tree): CaseDef = CaseDef(pat, EmptyTree, body) - - def Bind(sym: Symbol, body: Tree): Bind = - Bind(sym.name, body) setSymbol sym - - - /** Factory method for object creation `new tpt(args_1)...(args_n)` - * A `New(t, as)` is expanded to: `(new t).<init>(as)` - */ - def New(tpt: Tree, argss: List[List[Tree]]): Tree = { - assert(!argss.isEmpty) - val superRef: Tree = Select(New(tpt), nme.CONSTRUCTOR) - (superRef /: argss) (Apply) - } - - def Apply(sym: Symbol, args: Tree*): Tree = - Apply(Ident(sym), args.toList) - - def Super(sym: Symbol, mix: TypeName): Tree = Super(This(sym), mix) - - def This(sym: Symbol): Tree = This(sym.name.toTypeName) setSymbol sym - - def Select(qualifier: Tree, sym: Symbol): Select = - Select(qualifier, sym.name) setSymbol sym - - def Ident(sym: Symbol): Ident = - Ident(sym.name) setSymbol sym - - /** Block factory that flattens directly nested blocks. - */ - def Block(stats: Tree*): Block = stats match { - case Seq(b @ Block(_, _)) => b - case Seq(stat) => Block(stats.toList, Literal(Constant(()))) - case Seq(_, rest @ _*) => Block(stats.init.toList, stats.last) - } - - /** A synthetic term holding an arbitrary type. Not to be confused with - * with TypTree, the trait for trees that are only used for type trees. - * TypeTree's are inserted in several places, but most notably in - * <code>RefCheck</code>, where the arbitrary type trees are all replaced by - * TypeTree's. */ - case class TypeTree() extends AbsTypeTree { - private var orig: Tree = null - private[Trees] var wasEmpty: Boolean = false - - def original: Tree = orig - def setOriginal(tree: Tree): this.type = { - def followOriginal(t: Tree): Tree = t match { - case tt: TypeTree => followOriginal(tt.original) - case t => t - } - - orig = followOriginal(tree); setPos(tree.pos); - this - } - - override def defineType(tp: Type): this.type = { - wasEmpty = isEmpty - setType(tp) - } - } - - object TypeTree extends TypeTreeExtractor - - def TypeTree(tp: Type): TypeTree = TypeTree() setType tp - - /** Documented definition, eliminated by analyzer */ - case class DocDef(comment: DocComment, definition: Tree) - extends Tree { - override def symbol: Symbol = definition.symbol - override def symbol_=(sym: Symbol) { definition.symbol = sym } - // sean: seems to be important to the IDE - override def isDef = definition.isDef - } - - /** Either an assignment or a named argument. Only appears in argument lists, - * eliminated by typecheck (doTypedApply) - */ - case class AssignOrNamedArg(lhs: Tree, rhs: Tree) - extends TermTree - - case class Parens(args: List[Tree]) extends Tree // only used during parsing - - /** emitted by typer, eliminated by refchecks */ - case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends AbsTypeTree - -// ----- subconstructors -------------------------------------------- - - class ApplyToImplicitArgs(fun: Tree, args: List[Tree]) extends Apply(fun, args) - - class ApplyImplicitView(fun: Tree, args: List[Tree]) extends Apply(fun, args) - -// ----- auxiliary objects and methods ------------------------------ - - abstract class TreeCopier { - def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template): ClassDef - def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]): PackageDef - def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template): ModuleDef - def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree): ValDef - def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef - def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree): TypeDef - def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree): LabelDef - def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]): Import - def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef - def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]): Template - def Block(tree: Tree, stats: List[Tree], expr: Tree): Block - def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree): CaseDef - def Alternative(tree: Tree, trees: List[Tree]): Alternative - def Star(tree: Tree, elem: Tree): Star - def Bind(tree: Tree, name: Name, body: Tree): Bind - def UnApply(tree: Tree, fun: Tree, args: List[Tree]): UnApply - def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]): ArrayValue - def Function(tree: Tree, vparams: List[ValDef], body: Tree): Function - def Assign(tree: Tree, lhs: Tree, rhs: Tree): Assign - def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg - def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree): If - def Match(tree: Tree, selector: Tree, cases: List[CaseDef]): Match - def Return(tree: Tree, expr: Tree): Return - def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree): Try - def Throw(tree: Tree, expr: Tree): Throw - def New(tree: Tree, tpt: Tree): New - def Typed(tree: Tree, expr: Tree, tpt: Tree): Typed - def TypeApply(tree: Tree, fun: Tree, args: List[Tree]): TypeApply - def Apply(tree: Tree, fun: Tree, args: List[Tree]): Apply - def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]): ApplyDynamic - def Super(tree: Tree, qual: Tree, mix: TypeName): Super - def This(tree: Tree, qual: Name): This - def Select(tree: Tree, qualifier: Tree, selector: Name): Select - def Ident(tree: Tree, name: Name): Ident - def Literal(tree: Tree, value: Constant): Literal - def TypeTree(tree: Tree): TypeTree - def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck - def Annotated(tree: Tree, annot: Tree, arg: Tree): Annotated - def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree - def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name): SelectFromTypeTree - def CompoundTypeTree(tree: Tree, templ: Template): CompoundTypeTree - def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]): AppliedTypeTree - def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree): TypeBoundsTree - def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]): ExistentialTypeTree - def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray - } - - class StrictTreeCopier extends TreeCopier { - def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template) = - new ClassDef(mods, name.toTypeName, tparams, impl).copyAttrs(tree) - def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]) = - new PackageDef(pid, stats).copyAttrs(tree) - def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template) = - new ModuleDef(mods, name, impl).copyAttrs(tree) - def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) = - new ValDef(mods, name, tpt, rhs).copyAttrs(tree) - def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) = - new DefDef(mods, name, tparams, vparamss, tpt, rhs).copyAttrs(tree) - def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree) = - new TypeDef(mods, name.toTypeName, tparams, rhs).copyAttrs(tree) - def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) = - new LabelDef(name, params, rhs).copyAttrs(tree) - def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]) = - new Import(expr, selectors).copyAttrs(tree) - def DocDef(tree: Tree, comment: DocComment, definition: Tree) = - new DocDef(comment, definition).copyAttrs(tree) - def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]) = - new Template(parents, self, body).copyAttrs(tree) - def Block(tree: Tree, stats: List[Tree], expr: Tree) = - new Block(stats, expr).copyAttrs(tree) - def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) = - new CaseDef(pat, guard, body).copyAttrs(tree) - def Alternative(tree: Tree, trees: List[Tree]) = - new Alternative(trees).copyAttrs(tree) - def Star(tree: Tree, elem: Tree) = - new Star(elem).copyAttrs(tree) - def Bind(tree: Tree, name: Name, body: Tree) = - new Bind(name, body).copyAttrs(tree) - def UnApply(tree: Tree, fun: Tree, args: List[Tree]) = - new UnApply(fun, args).copyAttrs(tree) - def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]) = - new ArrayValue(elemtpt, trees).copyAttrs(tree) - def Function(tree: Tree, vparams: List[ValDef], body: Tree) = - new Function(vparams, body).copyAttrs(tree) - def Assign(tree: Tree, lhs: Tree, rhs: Tree) = - new Assign(lhs, rhs).copyAttrs(tree) - def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = - new AssignOrNamedArg(lhs, rhs).copyAttrs(tree) - def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = - new If(cond, thenp, elsep).copyAttrs(tree) - def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = - new Match(selector, cases).copyAttrs(tree) - def Return(tree: Tree, expr: Tree) = - new Return(expr).copyAttrs(tree) - def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) = - new Try(block, catches, finalizer).copyAttrs(tree) - def Throw(tree: Tree, expr: Tree) = - new Throw(expr).copyAttrs(tree) - def New(tree: Tree, tpt: Tree) = - new New(tpt).copyAttrs(tree) - def Typed(tree: Tree, expr: Tree, tpt: Tree) = - new Typed(expr, tpt).copyAttrs(tree) - def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) = - new TypeApply(fun, args).copyAttrs(tree) - def Apply(tree: Tree, fun: Tree, args: List[Tree]) = - (tree match { - case _: ApplyToImplicitArgs => new ApplyToImplicitArgs(fun, args) - case _: ApplyImplicitView => new ApplyImplicitView(fun, args) - case _ => new Apply(fun, args) - }).copyAttrs(tree) - def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) = - new ApplyDynamic(qual, args).copyAttrs(tree) - def Super(tree: Tree, qual: Tree, mix: TypeName) = - new Super(qual, mix).copyAttrs(tree) - def This(tree: Tree, qual: Name) = - new This(qual.toTypeName).copyAttrs(tree) - def Select(tree: Tree, qualifier: Tree, selector: Name) = - new Select(qualifier, selector).copyAttrs(tree) - def Ident(tree: Tree, name: Name) = - new Ident(name).copyAttrs(tree) - def Literal(tree: Tree, value: Constant) = - new Literal(value).copyAttrs(tree) - def TypeTree(tree: Tree) = - new TypeTree().copyAttrs(tree) - def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { - case dc@TypeTreeWithDeferredRefCheck() => new TypeTreeWithDeferredRefCheck()(dc.check).copyAttrs(tree) - } - def Annotated(tree: Tree, annot: Tree, arg: Tree) = - new Annotated(annot, arg).copyAttrs(tree) - def SingletonTypeTree(tree: Tree, ref: Tree) = - new SingletonTypeTree(ref).copyAttrs(tree) - def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) = - new SelectFromTypeTree(qualifier, selector.toTypeName).copyAttrs(tree) - def CompoundTypeTree(tree: Tree, templ: Template) = - new CompoundTypeTree(templ).copyAttrs(tree) - def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]) = - new AppliedTypeTree(tpt, args).copyAttrs(tree) - def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree) = - new TypeBoundsTree(lo, hi).copyAttrs(tree) - def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]) = - new ExistentialTypeTree(tpt, whereClauses).copyAttrs(tree) - def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = - new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree) - } - - class LazyTreeCopier(treeCopy: TreeCopier) extends TreeCopier { - def this() = this(new StrictTreeCopier) - def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template) = tree match { - case t @ ClassDef(mods0, name0, tparams0, impl0) - if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && (impl0 == impl) => t - case _ => treeCopy.ClassDef(tree, mods, name, tparams, impl) - } - def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]) = tree match { - case t @ PackageDef(pid0, stats0) - if (pid0 == pid) && (stats0 == stats) => t - case _ => treeCopy.PackageDef(tree, pid, stats) - } - def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template) = tree match { - case t @ ModuleDef(mods0, name0, impl0) - if (mods0 == mods) && (name0 == name) && (impl0 == impl) => t - case _ => treeCopy.ModuleDef(tree, mods, name, impl) - } - def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) = tree match { - case t @ ValDef(mods0, name0, tpt0, rhs0) - if (mods0 == mods) && (name0 == name) && (tpt0 == tpt) && (rhs0 == rhs) => t - case _ => treeCopy.ValDef(tree, mods, name, tpt, rhs) - } - def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) = tree match { - case t @ DefDef(mods0, name0, tparams0, vparamss0, tpt0, rhs0) - if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && - (vparamss0 == vparamss) && (tpt0 == tpt) && (rhs == rhs0) => t - case _ => treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs) - } - def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree) = tree match { - case t @ TypeDef(mods0, name0, tparams0, rhs0) - if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && (rhs0 == rhs) => t - case _ => treeCopy.TypeDef(tree, mods, name, tparams, rhs) - } - def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) = tree match { - case t @ LabelDef(name0, params0, rhs0) - if (name0 == name) && (params0 == params) && (rhs0 == rhs) => t - case _ => treeCopy.LabelDef(tree, name, params, rhs) - } - def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]) = tree match { - case t @ Import(expr0, selectors0) - if (expr0 == expr) && (selectors0 == selectors) => t - case _ => treeCopy.Import(tree, expr, selectors) - } - def DocDef(tree: Tree, comment: DocComment, definition: Tree) = tree match { - case t @ DocDef(comment0, definition0) - if (comment0 == comment) && (definition0 == definition) => t - case _ => treeCopy.DocDef(tree, comment, definition) - } - def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]) = tree match { - case t @ Template(parents0, self0, body0) - if (parents0 == parents) && (self0 == self) && (body0 == body) => t - case _ => treeCopy.Template(tree, parents, self, body) - } - def Block(tree: Tree, stats: List[Tree], expr: Tree) = tree match { - case t @ Block(stats0, expr0) - if ((stats0 == stats) && (expr0 == expr)) => t - case _ => treeCopy.Block(tree, stats, expr) - } - def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) = tree match { - case t @ CaseDef(pat0, guard0, body0) - if (pat0 == pat) && (guard0 == guard) && (body0 == body) => t - case _ => treeCopy.CaseDef(tree, pat, guard, body) - } - def Alternative(tree: Tree, trees: List[Tree]) = tree match { - case t @ Alternative(trees0) - if trees0 == trees => t - case _ => treeCopy.Alternative(tree, trees) - } - def Star(tree: Tree, elem: Tree) = tree match { - case t @ Star(elem0) - if elem0 == elem => t - case _ => treeCopy.Star(tree, elem) - } - def Bind(tree: Tree, name: Name, body: Tree) = tree match { - case t @ Bind(name0, body0) - if (name0 == name) && (body0 == body) => t - case _ => treeCopy.Bind(tree, name, body) - } - def UnApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { - case t @ UnApply(fun0, args0) - if (fun0 == fun) && (args0 == args) => t - case _ => treeCopy.UnApply(tree, fun, args) - } - def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]) = tree match { - case t @ ArrayValue(elemtpt0, trees0) - if (elemtpt0 == elemtpt) && (trees0 == trees) => t - case _ => treeCopy.ArrayValue(tree, elemtpt, trees) - } - def Function(tree: Tree, vparams: List[ValDef], body: Tree) = tree match { - case t @ Function(vparams0, body0) - if (vparams0 == vparams) && (body0 == body) => t - case _ => treeCopy.Function(tree, vparams, body) - } - def Assign(tree: Tree, lhs: Tree, rhs: Tree) = tree match { - case t @ Assign(lhs0, rhs0) - if (lhs0 == lhs) && (rhs0 == rhs) => t - case _ => treeCopy.Assign(tree, lhs, rhs) - } - def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = tree match { - case t @ AssignOrNamedArg(lhs0, rhs0) - if (lhs0 == lhs) && (rhs0 == rhs) => t - case _ => treeCopy.AssignOrNamedArg(tree, lhs, rhs) - } - def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = tree match { - case t @ If(cond0, thenp0, elsep0) - if (cond0 == cond) && (thenp0 == thenp) && (elsep0 == elsep) => t - case _ => treeCopy.If(tree, cond, thenp, elsep) - } - def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = tree match { - case t @ Match(selector0, cases0) - if (selector0 == selector) && (cases0 == cases) => t - case _ => treeCopy.Match(tree, selector, cases) - } - def Return(tree: Tree, expr: Tree) = tree match { - case t @ Return(expr0) - if expr0 == expr => t - case _ => treeCopy.Return(tree, expr) - } - def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) = tree match { - case t @ Try(block0, catches0, finalizer0) - if (block0 == block) && (catches0 == catches) && (finalizer0 == finalizer) => t - case _ => treeCopy.Try(tree, block, catches, finalizer) - } - def Throw(tree: Tree, expr: Tree) = tree match { - case t @ Throw(expr0) - if expr0 == expr => t - case _ => treeCopy.Throw(tree, expr) - } - def New(tree: Tree, tpt: Tree) = tree match { - case t @ New(tpt0) - if tpt0 == tpt => t - case _ => treeCopy.New(tree, tpt) - } - def Typed(tree: Tree, expr: Tree, tpt: Tree) = tree match { - case t @ Typed(expr0, tpt0) - if (expr0 == expr) && (tpt0 == tpt) => t - case _ => treeCopy.Typed(tree, expr, tpt) - } - def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { - case t @ TypeApply(fun0, args0) - if (fun0 == fun) && (args0 == args) => t - case _ => treeCopy.TypeApply(tree, fun, args) - } - def Apply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { - case t @ Apply(fun0, args0) - if (fun0 == fun) && (args0 == args) => t - case _ => treeCopy.Apply(tree, fun, args) - } - def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) = tree match { - case t @ ApplyDynamic(qual0, args0) - if (qual0 == qual) && (args0 == args) => t - case _ => treeCopy.ApplyDynamic(tree, qual, args) - } - def Super(tree: Tree, qual: Tree, mix: TypeName) = tree match { - case t @ Super(qual0, mix0) - if (qual0 == qual) && (mix0 == mix) => t - case _ => treeCopy.Super(tree, qual, mix) - } - def This(tree: Tree, qual: Name) = tree match { - case t @ This(qual0) - if qual0 == qual => t - case _ => treeCopy.This(tree, qual) - } - def Select(tree: Tree, qualifier: Tree, selector: Name) = tree match { - case t @ Select(qualifier0, selector0) - if (qualifier0 == qualifier) && (selector0 == selector) => t - case _ => treeCopy.Select(tree, qualifier, selector) - } - def Ident(tree: Tree, name: Name) = tree match { - case t @ Ident(name0) - if name0 == name => t - case _ => treeCopy.Ident(tree, name) - } - def Literal(tree: Tree, value: Constant) = tree match { - case t @ Literal(value0) - if value0 == value => t - case _ => treeCopy.Literal(tree, value) - } - def TypeTree(tree: Tree) = tree match { - case t @ TypeTree() => t - case _ => treeCopy.TypeTree(tree) - } - def TypeTreeWithDeferredRefCheck(tree: Tree) = tree match { - case t @ TypeTreeWithDeferredRefCheck() => t - case _ => treeCopy.TypeTreeWithDeferredRefCheck(tree) - } - def Annotated(tree: Tree, annot: Tree, arg: Tree) = tree match { - case t @ Annotated(annot0, arg0) - if (annot0==annot) => t - case _ => treeCopy.Annotated(tree, annot, arg) - } - def SingletonTypeTree(tree: Tree, ref: Tree) = tree match { - case t @ SingletonTypeTree(ref0) - if ref0 == ref => t - case _ => treeCopy.SingletonTypeTree(tree, ref) - } - def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) = tree match { - case t @ SelectFromTypeTree(qualifier0, selector0) - if (qualifier0 == qualifier) && (selector0 == selector) => t - case _ => treeCopy.SelectFromTypeTree(tree, qualifier, selector) - } - def CompoundTypeTree(tree: Tree, templ: Template) = tree match { - case t @ CompoundTypeTree(templ0) - if templ0 == templ => t - case _ => treeCopy.CompoundTypeTree(tree, templ) - } - def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]) = tree match { - case t @ AppliedTypeTree(tpt0, args0) - if (tpt0 == tpt) && (args0 == args) => t - case _ => treeCopy.AppliedTypeTree(tree, tpt, args) - } - def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree) = tree match { - case t @ TypeBoundsTree(lo0, hi0) - if (lo0 == lo) && (hi0 == hi) => t - case _ => treeCopy.TypeBoundsTree(tree, lo, hi) - } - def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]) = tree match { - case t @ ExistentialTypeTree(tpt0, whereClauses0) - if (tpt0 == tpt) && (whereClauses0 == whereClauses) => t - case _ => treeCopy.ExistentialTypeTree(tree, tpt, whereClauses) - } - def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = tree match { - case t @ SelectFromArray(qualifier0, selector0, _) - if (qualifier0 == qualifier) && (selector0 == selector) => t - case _ => treeCopy.SelectFromArray(tree, qualifier, selector, erasure) - } - } - - abstract class Transformer { - val treeCopy: TreeCopier = new LazyTreeCopier - protected var currentOwner: Symbol = definitions.RootClass - protected def currentMethod = currentOwner.enclMethod - protected def currentClass = currentOwner.enclClass - protected def currentPackage = currentOwner.toplevelClass.owner - def transform(tree: Tree): Tree = tree match { - case EmptyTree => - tree - case PackageDef(pid, stats) => - treeCopy.PackageDef( - tree, transform(pid).asInstanceOf[RefTree], - atOwner(tree.symbol.moduleClass) { - transformStats(stats, currentOwner) - } - ) - case ClassDef(mods, name, tparams, impl) => - atOwner(tree.symbol) { - treeCopy.ClassDef(tree, transformModifiers(mods), name, - transformTypeDefs(tparams), transformTemplate(impl)) - } - case ModuleDef(mods, name, impl) => - atOwner(tree.symbol.moduleClass) { - treeCopy.ModuleDef(tree, transformModifiers(mods), - name, transformTemplate(impl)) - } - case ValDef(mods, name, tpt, rhs) => - atOwner(tree.symbol) { - treeCopy.ValDef(tree, transformModifiers(mods), - name, transform(tpt), transform(rhs)) - } - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - atOwner(tree.symbol) { - treeCopy.DefDef(tree, transformModifiers(mods), name, - transformTypeDefs(tparams), transformValDefss(vparamss), - transform(tpt), transform(rhs)) - } - case TypeDef(mods, name, tparams, rhs) => - atOwner(tree.symbol) { - treeCopy.TypeDef(tree, transformModifiers(mods), name, - transformTypeDefs(tparams), transform(rhs)) - } - case LabelDef(name, params, rhs) => - treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy' - case Import(expr, selectors) => - treeCopy.Import(tree, transform(expr), selectors) - case DocDef(comment, definition) => - treeCopy.DocDef(tree, comment, transform(definition)) - case Template(parents, self, body) => - treeCopy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol)) - case Block(stats, expr) => - treeCopy.Block(tree, transformStats(stats, currentOwner), transform(expr)) - case CaseDef(pat, guard, body) => - treeCopy.CaseDef(tree, transform(pat), transform(guard), transform(body)) - case Alternative(trees) => - treeCopy.Alternative(tree, transformTrees(trees)) - case Star(elem) => - treeCopy.Star(tree, transform(elem)) - case Bind(name, body) => - treeCopy.Bind(tree, name, transform(body)) - case UnApply(fun, args) => - treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala - case ArrayValue(elemtpt, trees) => - treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees)) - case Function(vparams, body) => - atOwner(tree.symbol) { - treeCopy.Function(tree, transformValDefs(vparams), transform(body)) - } - case Assign(lhs, rhs) => - treeCopy.Assign(tree, transform(lhs), transform(rhs)) - case AssignOrNamedArg(lhs, rhs) => - treeCopy.AssignOrNamedArg(tree, transform(lhs), transform(rhs)) - case If(cond, thenp, elsep) => - treeCopy.If(tree, transform(cond), transform(thenp), transform(elsep)) - case Match(selector, cases) => - treeCopy.Match(tree, transform(selector), transformCaseDefs(cases)) - case Return(expr) => - treeCopy.Return(tree, transform(expr)) - case Try(block, catches, finalizer) => - treeCopy.Try(tree, transform(block), transformCaseDefs(catches), transform(finalizer)) - case Throw(expr) => - treeCopy.Throw(tree, transform(expr)) - case New(tpt) => - treeCopy.New(tree, transform(tpt)) - case Typed(expr, tpt) => - treeCopy.Typed(tree, transform(expr), transform(tpt)) - case TypeApply(fun, args) => - treeCopy.TypeApply(tree, transform(fun), transformTrees(args)) - case Apply(fun, args) => - treeCopy.Apply(tree, transform(fun), transformTrees(args)) - case ApplyDynamic(qual, args) => - treeCopy.ApplyDynamic(tree, transform(qual), transformTrees(args)) - case Super(qual, mix) => - treeCopy.Super(tree, transform(qual), mix) - case This(qual) => - treeCopy.This(tree, qual) - case Select(qualifier, selector) => - treeCopy.Select(tree, transform(qualifier), selector) - case Ident(name) => - treeCopy.Ident(tree, name) - case Literal(value) => - treeCopy.Literal(tree, value) - case TypeTree() => - treeCopy.TypeTree(tree) - case TypeTreeWithDeferredRefCheck() => - treeCopy.TypeTreeWithDeferredRefCheck(tree) - case Annotated(annot, arg) => - treeCopy.Annotated(tree, transform(annot), transform(arg)) - case SingletonTypeTree(ref) => - treeCopy.SingletonTypeTree(tree, transform(ref)) - case SelectFromTypeTree(qualifier, selector) => - treeCopy.SelectFromTypeTree(tree, transform(qualifier), selector) - case CompoundTypeTree(templ) => - treeCopy.CompoundTypeTree(tree, transformTemplate(templ)) - case AppliedTypeTree(tpt, args) => - treeCopy.AppliedTypeTree(tree, transform(tpt), transformTrees(args)) - case TypeBoundsTree(lo, hi) => - treeCopy.TypeBoundsTree(tree, transform(lo), transform(hi)) - case ExistentialTypeTree(tpt, whereClauses) => - treeCopy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses)) - case SelectFromArray(qualifier, selector, erasure) => - treeCopy.SelectFromArray(tree, transform(qualifier), selector, erasure) - } - - def transformTrees(trees: List[Tree]): List[Tree] = - trees mapConserve (transform(_)) - def transformTemplate(tree: Template): Template = - transform(tree: Tree).asInstanceOf[Template] - def transformTypeDefs(trees: List[TypeDef]): List[TypeDef] = - trees mapConserve (tree => transform(tree).asInstanceOf[TypeDef]) - def transformValDef(tree: ValDef): ValDef = - if (tree.isEmpty) tree else transform(tree).asInstanceOf[ValDef] - def transformValDefs(trees: List[ValDef]): List[ValDef] = - trees mapConserve (transformValDef(_)) - def transformValDefss(treess: List[List[ValDef]]): List[List[ValDef]] = - treess mapConserve (transformValDefs(_)) - def transformCaseDefs(trees: List[CaseDef]): List[CaseDef] = - trees mapConserve (tree => transform(tree).asInstanceOf[CaseDef]) - def transformIdents(trees: List[Ident]): List[Ident] = - trees mapConserve (tree => transform(tree).asInstanceOf[Ident]) - def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = - stats mapConserve (stat => - if (exprOwner != currentOwner && stat.isTerm) atOwner(exprOwner)(transform(stat)) - else transform(stat)) filter (EmptyTree !=) + class Transformer extends super.Transformer { def transformUnit(unit: CompilationUnit) { unit.body = transform(unit.body) } - def transformModifiers(mods: Modifiers): Modifiers = - Modifiers(mods.flags, mods.privateWithin, transformTrees(mods.annotations), mods.positions) - - def atOwner[A](owner: Symbol)(trans: => A): A = { - val prevOwner = currentOwner - currentOwner = owner - val result = trans - currentOwner = prevOwner - result - } - } - - class Traverser extends super.Traverser { - /** Compiler specific tree types are handled here: the remainder are in - * the library's abstract tree traverser. - */ - override def traverse(tree: Tree): Unit = tree match { - case AssignOrNamedArg(lhs, rhs) => - traverse(lhs); traverse(rhs) - case DocDef(comment, definition) => - traverse(definition) - case Parens(ts) => - traverseTrees(ts) - case TypeTreeWithDeferredRefCheck() => // TODO: should we traverse the wrapped tree? - // (and rewrap the result? how to update the deferred check? would need to store wrapped tree instead of returning it from check) - case Super(qual, _) => - traverse(qual) // !!! remove when Super is done - case _ => super.traverse(tree) - } - - /** The abstract traverser is not aware of Tree.isTerm, so we override this one. - */ - override def traverseStats(stats: List[Tree], exprOwner: Symbol) { - stats foreach (stat => - if (exprOwner != currentOwner && stat.isTerm) atOwner(exprOwner)(traverse(stat)) - else traverse(stat) - ) - } - - /** Leave apply available in the generic traverser to do something else. - */ - def apply[T <: Tree](tree: T): T = { traverse(tree); tree } } - - private lazy val duplicator = new Transformer { - override val treeCopy = new StrictTreeCopier - override def transform(t: Tree) = { - val t1 = super.transform(t) - if ((t1 ne t) && t1.pos.isRange) t1 setPos t.pos.focus - t1 - } - } - - private class ShallowDuplicator(orig: Tree) extends Transformer { - override val treeCopy = new StrictTreeCopier - override def transform(tree: Tree) = - if (tree eq orig) super.transform(tree) - else tree - } - - class TreeSubstituter(from: List[Symbol], to: List[Tree]) extends Transformer { - override def transform(tree: Tree): Tree = tree match { - case Ident(_) => - def subst(from: List[Symbol], to: List[Tree]): Tree = - if (from.isEmpty) tree - else if (tree.symbol == from.head) to.head - else subst(from.tail, to.tail); - subst(from, to) - case _ => - super.transform(tree) - } - } - - class TreeTypeSubstituter(val from: List[Symbol], val to: List[Type]) extends Traverser { - val typeSubst = new SubstTypeMap(from, to) - def fromContains = typeSubst.fromContains - - override def traverse(tree: Tree) { - if (tree.tpe ne null) tree.tpe = typeSubst(tree.tpe) - if (tree.isDef) { - val sym = tree.symbol - val info1 = typeSubst(sym.info) - if (info1 ne sym.info) sym.setInfo(info1) - } - super.traverse(tree) - } - override def apply[T <: Tree](tree: T): T = super.apply(tree.duplicate) - override def toString() = "TreeTypeSubstituter("+from+","+to+")" - } - - lazy val EmptyTreeTypeSubstituter = new TreeTypeSubstituter(List(), List()) - - class TreeSymSubstTraverser(val from: List[Symbol], val to: List[Symbol]) extends Traverser { - val subst = new SubstSymMap(from, to) - override def traverse(tree: Tree) { - if (tree.tpe ne null) tree.tpe = subst(tree.tpe) - if (tree.isDef) { - val sym = tree.symbol - val info1 = subst(sym.info) - if (info1 ne sym.info) sym.setInfo(info1) - } - super.traverse(tree) - } - override def apply[T <: Tree](tree: T): T = super.apply(tree.duplicate) - override def toString() = "TreeSymSubstTraverser("+from+","+to+")" - } - - /** Substitute symbols in 'from' with symbols in 'to'. Returns a new - * tree using the new symbols and whose Ident and Select nodes are - * name-consistent with the new symbols. - */ - class TreeSymSubstituter(from: List[Symbol], to: List[Symbol]) extends Transformer { - val symSubst = new SubstSymMap(from, to) - override def transform(tree: Tree): Tree = { - def subst(from: List[Symbol], to: List[Symbol]) { - if (!from.isEmpty) - if (tree.symbol == from.head) tree setSymbol to.head - else subst(from.tail, to.tail) - } - - if (tree.tpe ne null) tree.tpe = symSubst(tree.tpe) - if (tree.hasSymbol) { - subst(from, to) - tree match { - case Ident(name0) if tree.symbol != NoSymbol => - treeCopy.Ident(tree, tree.symbol.name) - case Select(qual, name0) => - treeCopy.Select(tree, transform(qual), tree.symbol.name) - case _ => - super.transform(tree) - } - } else - super.transform(tree) - } - def apply[T <: Tree](tree: T): T = transform(tree).asInstanceOf[T] - override def toString() = "TreeSymSubstituter("+from+","+to+")" - } - - class ChangeOwnerTraverser(val oldowner: Symbol, val newowner: Symbol) extends Traverser { - def changeOwner(tree: Tree) = { - if ((tree.isDef || tree.isInstanceOf[Function]) && - tree.symbol != NoSymbol && tree.symbol.owner == oldowner) - tree.symbol.owner = newowner - } - override def traverse(tree: Tree) { - changeOwner(tree) - super.traverse(tree) - } - } - - object posAssigner extends Traverser { - var pos: Position = _ - override def traverse(t: Tree) { - if (t != EmptyTree && t.pos == NoPosition) { - t.setPos(pos) - super.traverse(t) - } - } - } - - def atPos[T <: Tree](pos: Position)(tree: T): T = { - posAssigner.pos = pos - posAssigner.traverse(tree) - tree - } - - class ForeachPartialTreeTraverser(pf: PartialFunction[Tree, Tree]) extends Traverser { - override def traverse(tree: Tree) { - val t = if (pf isDefinedAt tree) pf(tree) else tree - super.traverse(t) - } - } - - class ForeachTreeTraverser(f: Tree => Unit) extends Traverser { - override def traverse(t: Tree) { - f(t) - super.traverse(t) - } - } - - class FilterTreeTraverser(p: Tree => Boolean) extends Traverser { - val hits = new ListBuffer[Tree] - override def traverse(t: Tree) { - if (p(t)) hits += t - super.traverse(t) - } - } - - class FindTreeTraverser(p: Tree => Boolean) extends Traverser { - var result: Option[Tree] = None - override def traverse(t: Tree) { - if (result.isEmpty) { - if (p(t)) result = Some(t) - super.traverse(t) - } - } - } - - object resetPos extends Traverser { - override def traverse(t: Tree) { - if (t != EmptyTree) t.setPos(NoPosition) - super.traverse(t) - } - } - - - /** resets symbol and tpe fields in a tree, @see ResetAttrsTraverse - */ - def resetAllAttrs[A<:Tree](x:A): A = { new ResetAttrsTraverser().traverse(x); x } - def resetLocalAttrs[A<:Tree](x:A): A = { new ResetLocalAttrsTraverser().traverse(x); x } - - /** A traverser which resets symbol and tpe fields of all nodes in a given tree - * except for (1) TypeTree nodes, whose <code>.tpe</code> field is kept, and - * (2) This(pkg) nodes, where pkg refers to a package symbol -- their attributes are kept, and - * (3) if a <code>.symbol</code> field refers to a symbol which is defined - * outside the tree, it is also kept. - * - * (2) is necessary because some This(pkg) are generated where pkg is not - * an enclosing package.n In that case, resetting the symbol would cause the - * next type checking run to fail. See #3152. - * - * (bq:) This traverser has mutable state and should be discarded after use - */ - private class ResetAttrsTraverser extends Traverser { - protected def isLocal(sym: Symbol): Boolean = true - protected def resetDef(tree: Tree) { - tree.symbol = NoSymbol - } - override def traverse(tree: Tree): Unit = { - tree match { - case _: DefTree | Function(_, _) | Template(_, _, _) => - resetDef(tree) - tree.tpe = null - case tpt: TypeTree => - if (tpt.wasEmpty) tree.tpe = null - case This(_) if tree.symbol != null && tree.symbol.isPackageClass => - ; - case EmptyTree => - ; - case _ => - if (tree.hasSymbol && isLocal(tree.symbol)) tree.symbol = NoSymbol - tree.tpe = null - } - super.traverse(tree) - } - } - - private class ResetLocalAttrsTraverser extends ResetAttrsTraverser { - private val erasedSyms = HashSet[Symbol](8) - override protected def isLocal(sym: Symbol) = erasedSyms(sym) - override protected def resetDef(tree: Tree) { - erasedSyms addEntry tree.symbol - super.resetDef(tree) - } - override def traverse(tree: Tree): Unit = tree match { - case Template(parents, self, body) => - for (stat <- body) - if (stat.isDef) erasedSyms.addEntry(stat.symbol) - super.traverse(tree) - case _ => - super.traverse(tree) - } - } -} - +}
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index a3fd44fa47..fa81c3f033 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -12,7 +12,7 @@ import scala.util.control.ControlThrowable import scala.tools.nsc.util.{SourceFile,CharArrayReader} import scala.xml.{ Text, TextBuffer } import scala.xml.Utility.{ isNameStart, isNameChar, isSpace } -import util.Chars.{ SU, LF } +import scala.reflect.Chars.{ SU, LF } // XXX/Note: many/most of the functions in here are almost direct cut and pastes // from another file - scala.xml.parsing.MarkupParser, it looks like. diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 086b72be56..e1d45ac8ca 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -11,9 +11,9 @@ package ast.parser import scala.collection.mutable.ListBuffer import util.{ SourceFile, OffsetPosition, FreshNameCreator } -import scala.reflect.generic.{ ModifierFlags => Flags } +import scala.reflect.common.{ ModifierFlags => Flags } import Tokens._ -import util.Chars.{ isScalaLetter } +import scala.reflect.Chars.{ isScalaLetter } /** Historical note: JavaParsers started life as a direct copy of Parsers * but at a time when that Parsers had been replaced by a different one. diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index 528705b03d..aa862653d6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -28,7 +28,7 @@ abstract class SymbolicXMLBuilder(p: Parsers#Parser, preserveWS: Boolean) { var isPattern: Boolean = _ - trait XMLTypeNames extends LibraryTypeNames { + trait XMLTypeNames extends TypeNames { val _Comment: NameType = "Comment" val _Elem: NameType = "Elem" val _EntityRef: NameType = "EntityRef" @@ -43,7 +43,7 @@ abstract class SymbolicXMLBuilder(p: Parsers#Parser, preserveWS: Boolean) { val _UnprefixedAttribute: NameType = "UnprefixedAttribute" } - trait XMLTermNames extends LibraryTermNames { + trait XMLTermNames extends TermNames { val _Null: NameType = "Null" val __Elem: NameType = "Elem" val __Text: NameType = "Text" @@ -63,8 +63,11 @@ abstract class SymbolicXMLBuilder(p: Parsers#Parser, preserveWS: Boolean) { type NameType = TermName implicit def createNameType(name: String): TermName = newTermName(name) } - import xmltypes._ - import xmlterms._ + + import xmltypes.{_Comment, _Elem, _EntityRef, _Group, _MetaData, _NamespaceBinding, _NodeBuffer, + _PrefixedAttribute, _ProcInstr, _Text, _Unparsed, _UnprefixedAttribute} + + import xmlterms.{_Null, __Elem, __Text, _buf, _md, _plus, _scope, _tmpscope, _xml} // convenience methods private def LL[A](x: A*): List[List[A]] = List(List(x:_*)) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala index 2f0d86c993..fb3d79a3c7 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala @@ -8,7 +8,7 @@ package backend.jvm import ch.epfl.lamp.fjbg._ import java.io.{ DataOutputStream, OutputStream } -import scala.tools.nsc.io.{ AbstractFile, Path } +import scala.tools.nsc.io.Path import scala.tools.nsc.util.ScalaClassLoader import scala.tools.util.Javap import java.util.jar.{ JarEntry, JarOutputStream } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 76e0162593..4c584cd4b5 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -10,9 +10,8 @@ package backend.jvm import java.io.{ DataOutputStream, OutputStream } import java.nio.ByteBuffer import scala.collection.{ mutable, immutable } -import scala.reflect.generic.{ PickleFormat, PickleBuffer } +import scala.reflect.common.pickling.{ PickleFormat, PickleBuffer } import scala.tools.reflect.SigParser -import scala.tools.nsc.io.{ AbstractFile, Path } import scala.tools.nsc.util.ScalaClassLoader import scala.tools.nsc.symtab._ import scala.tools.nsc.symtab.classfile.ClassfileConstants._ diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index 1968ca56aa..7abba299b5 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -24,6 +24,8 @@ abstract class GenMSIL extends SubComponent { import icodes._ import icodes.opcodes._ + val x = loaders + /** Create a new phase */ override def newPhase(p: Phase) = new MsilPhase(p) diff --git a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala index b2a93873b0..41eb01704f 100644 --- a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala +++ b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala @@ -2,7 +2,7 @@ package scala.tools.nsc package dependencies import util.SourceFile -import io.{ AbstractFile, Path } +import io.Path import collection._ import symtab.Flags diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index ba15ea8aed..ac31b20aa5 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -66,11 +66,11 @@ trait CompilerControl { self: Global => * if it does not yet exist create a new one atomically * Note: We want to get roid of this operation as it messes compiler invariants. */ - @deprecated("use getUnitOf(s) or onUnitOf(s) instead", "2.9.0") + @deprecated("use getUnitOf(s) or onUnitOf(s) instead") def unitOf(s: SourceFile): RichCompilationUnit = getOrCreateUnitOf(s) /** The compilation unit corresponding to a position */ - @deprecated("use getUnitOf(pos.source) or onUnitOf(pos.source) instead", "2.9.0") + @deprecated("use getUnitOf(pos.source) or onUnitOf(pos.source) instead") def unitOf(pos: Position): RichCompilationUnit = getOrCreateUnitOf(pos.source) /** Removes the CompilationUnit corresponding to the given SourceFile @@ -211,7 +211,7 @@ trait CompilerControl { self: Global => /** Tells the compile server to shutdown, and not to restart again */ def askShutdown() = scheduler raise ShutdownReq - @deprecated("use parseTree(source) instead", "2.9.0") + @deprecated("use parseTree(source) instead") // deleted 2nd parameter, as thius has to run on 2.8 also. def askParse(source: SourceFile, response: Response[Tree]) = respond(response) { parseTree(source) } diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index da97e10584..694df32e32 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -20,7 +20,7 @@ import scala.tools.nsc.ast._ import scala.tools.nsc.io.Pickler._ import scala.tools.nsc.typechecker.DivergentImplicit import scala.annotation.tailrec -import scala.reflect.generic.Flags.{ACCESSOR, PARAMACCESSOR} +import symtab.Flags.{ACCESSOR, PARAMACCESSOR} /** The main class of the presentation compiler in an interactive environment such as an IDE */ diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala index 27947d5e0e..2690a6c79b 100644 --- a/src/compiler/scala/tools/nsc/interactive/REPL.scala +++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala @@ -60,7 +60,7 @@ object REPL { def main(args: Array[String]) { process(args) - sys.exit(if (reporter.hasErrors) 1 else 0) + exit(if (reporter.hasErrors) 1 else 0) } def loop(action: (String) => Unit) { @@ -134,7 +134,8 @@ object REPL { doComplete(makePos(file, off1, off1)) case List("quit") => comp.askShutdown() - sys.exit(1) + // deleted sys. as this has to run on 2.8 also + exit(1) case List("structure", file) => doStructure(file) case _ => diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala index 67cf037a3a..3a1a9d5bd9 100644 --- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala @@ -113,8 +113,8 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana // See if we really have corresponding symbols, not just those // which share the name def isCorrespondingSym(from: Symbol, to: Symbol): Boolean = - (from.hasTraitFlag == to.hasTraitFlag) && - (from.hasModuleFlag == to.hasModuleFlag) + (from.hasFlag(Flags.TRAIT) == to.hasFlag(Flags.TRAIT)) && // has to run in 2.8, so no hasTraitFlag + (from.hasFlag(Flags.MODULE) == to.hasFlag(Flags.MODULE)) // For testing purposes only, order irrelevant for compilation def toStringSet(set: Set[AbstractFile]): String = diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 69858e8bba..fdf8f6bfab 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -10,10 +10,11 @@ import Predef.{ println => _, _ } import java.io.{ PrintWriter } import java.lang.reflect import java.net.URL -import util.{ Set => _, _ } -import io.{ AbstractFile, VirtualDirectory } +import util._ +import io.VirtualDirectory import reporters.{ ConsoleReporter, Reporter } -import symtab.{ Flags, Names } +import symtab.Flags +import scala.reflect.common.Names import scala.tools.nsc.interpreter.{ Results => IR } import scala.tools.util.PathResolver import scala.tools.nsc.util.{ ScalaClassLoader, Exceptional } diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala index e4921bd898..385e181404 100644 --- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -9,7 +9,7 @@ package interpreter import scala.collection.{ mutable, immutable } import scala.PartialFunction.cond import scala.reflect.NameTransformer -import util.Chars +import scala.reflect.Chars trait MemberHandlers { val intp: IMain diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplStrings.scala b/src/compiler/scala/tools/nsc/interpreter/ReplStrings.scala index cef46c963a..d14f4cefae 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplStrings.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplStrings.scala @@ -9,7 +9,7 @@ package interpreter import scala.collection.{ mutable, immutable } import scala.PartialFunction.cond import scala.reflect.NameTransformer -import util.Chars +import scala.reflect.Chars trait ReplStrings { // Longest common prefix diff --git a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala index 82e311028b..b87e556d7c 100644 --- a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala @@ -13,7 +13,7 @@ import io.AbstractFile * interchangeably. Except of course without the mutants. */ -trait AbsSettings { +trait AbsSettings extends scala.reflect.common.settings.AbsSettings { type Setting <: AbsSetting // Fix to the concrete Setting type type ResultOfTryToSet // List[String] in mutable, (Settings, List[String]) in immutable def errorFn: String => Unit @@ -51,12 +51,6 @@ trait AbsSettings { implicit lazy val SettingOrdering: Ordering[Setting] = Ordering.ordered - trait AbsSettingValue { - type T <: Any - def value: T - def isDefault: Boolean - } - trait AbsSetting extends Ordered[Setting] with AbsSettingValue { def name: String def helpDescription: String diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index 87398e4117..e38ccd2b80 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -15,7 +15,8 @@ import scala.io.Source /** A mutable Settings object. */ -class MutableSettings(val errorFn: String => Unit) extends AbsSettings with ScalaSettings with Mutable { +class MutableSettings(val errorFn: String => Unit) extends scala.reflect.common.settings.MutableSettings + with AbsSettings with ScalaSettings with Mutable { type ResultOfTryToSet = List[String] /** Iterates over the arguments applying them to settings where applicable. @@ -201,21 +202,6 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal } def PrefixSetting(name: String, prefix: String, descr: String): PrefixSetting = add(new PrefixSetting(name, prefix, descr)) - // basically this is a value which remembers if it's been modified - trait SettingValue extends AbsSettingValue { - protected var v: T - protected var setByUser: Boolean = false - def postSetHook(): Unit - - def isDefault: Boolean = !setByUser - def value: T = v - def value_=(arg: T) = { - setByUser = true - v = arg - postSetHook() - } - } - /** A class for holding mappings from source directories to * their output location. This functionality can be accessed * only programmatically. The command line compiler uses a diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala index d26c5d65a0..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala +++ b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala @@ -1,120 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2007-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package symtab - -/** Additions to the type checker that can be added at - * run time. Typically these are added by - * compiler plugins. */ -trait AnnotationCheckers { - self: SymbolTable => - - - /** An additional checker for annotations on types. - * Typically these are registered by compiler plugins - * with the addAnnotationChecker method. */ - abstract class AnnotationChecker { - /** Check the annotations on two types conform. */ - def annotationsConform(tpe1: Type, tpe2: Type): Boolean - - /** Refine the computed least upper bound of a list of types. - * All this should do is add annotations. */ - def annotationsLub(tp: Type, ts: List[Type]): Type = tp - - /** Refine the computed greatest lower bound of a list of types. - * All this should do is add annotations. */ - def annotationsGlb(tp: Type, ts: List[Type]): Type = tp - - /** Refine the bounds on type parameters to the given type arguments. */ - def adaptBoundsToAnnotations(bounds: List[TypeBounds], - tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = bounds - - /** Modify the type that has thus far been inferred - * for a tree. All this should do is add annotations. */ - def addAnnotations(tree: Tree, tpe: Type): Type = tpe - - /** Decide whether this annotation checker can adapt a tree - * that has an annotated type to the given type tp, taking - * into account the given mode (see method adapt in trait Typers).*/ - def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = false - - /** Adapt a tree that has an annotated type to the given type tp, - * taking into account the given mode (see method adapt in trait Typers). - * An implementation cannot rely on canAdaptAnnotations being called - * before. If the implementing class cannot do the adaptiong, it - * should return the tree unchanged.*/ - def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = tree - } - - /** The list of annotation checkers that have been registered */ - private var annotationCheckers: List[AnnotationChecker] = Nil - - /** Register an annotation checker. Typically these - * are added by compiler plugins. */ - def addAnnotationChecker(checker: AnnotationChecker) { - if (!(annotationCheckers contains checker)) - annotationCheckers = checker :: annotationCheckers - } - - /** Remove all annotation checkers */ - def removeAllAnnotationCheckers() { - annotationCheckers = Nil - } - - /** Check that the annotations on two types conform. To do - * so, consult all registered annotation checkers. */ - def annotationsConform(tp1: Type, tp2: Type): Boolean = { - /* Finish quickly if there are no annotations */ - if (tp1.annotations.isEmpty && tp2.annotations.isEmpty) - true - else - annotationCheckers.forall( - _.annotationsConform(tp1,tp2)) - } - - /** Refine the computed least upper bound of a list of types. - * All this should do is add annotations. */ - def annotationsLub(tpe: Type, ts: List[Type]): Type = { - annotationCheckers.foldLeft(tpe)((tpe, checker) => - checker.annotationsLub(tpe, ts)) - } - - /** Refine the computed greatest lower bound of a list of types. - * All this should do is add annotations. */ - def annotationsGlb(tpe: Type, ts: List[Type]): Type = { - annotationCheckers.foldLeft(tpe)((tpe, checker) => - checker.annotationsGlb(tpe, ts)) - } - - /** Refine the bounds on type parameters to the given type arguments. */ - def adaptBoundsToAnnotations(bounds: List[TypeBounds], - tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = { - annotationCheckers.foldLeft(bounds)((bounds, checker) => - checker.adaptBoundsToAnnotations(bounds, tparams, targs)) - } - - /** Let all annotations checkers add extra annotations - * to this tree's type. */ - def addAnnotations(tree: Tree, tpe: Type): Type = { - annotationCheckers.foldLeft(tpe)((tpe, checker) => - checker.addAnnotations(tree, tpe)) - } - - /** Find out whether any annotation checker can adapt a tree - * to a given type. Called by Typers.adapt. */ - def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = { - annotationCheckers.exists(_.canAdaptAnnotations(tree, mode, pt)) - } - - /** Let registered annotation checkers adapt a tree - * to a given type (called by Typers.adapt). Annotation checkers - * that cannot do the adaption should pass the tree through - * unchanged. */ - def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = { - annotationCheckers.foldLeft(tree)((tree, checker) => - checker.adaptAnnotations(tree, mode, pt)) - } -} diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala index 3c67814346..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala +++ b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala @@ -1,152 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2007-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package symtab - -import scala.tools.nsc.transform.Reifiers -import util._ - -/** AnnotationInfo and its helpers */ -trait AnnotationInfos extends reflect.generic.AnnotationInfos { self: SymbolTable => - - /** Arguments to classfile annotations (which are written to - * bytecode as java annotations) are either: - * <ul> - * <li>constants</li> - * <li>arrays of constants</li> - * <li>or nested classfile annotations</li> - * </ul> - */ - abstract class ClassfileAnnotArg - - /** Represents a compile-time Constant (Boolean, Byte, Short, - * Char, Int, Long, Float, Double, String, java.lang.Class or - * an instance of a Java enumeration value). - */ - case class LiteralAnnotArg(const: Constant) - extends ClassfileAnnotArg { - override def toString = const.escapedStringValue - } - - object LiteralAnnotArg extends LiteralAnnotArgExtractor - - /** Represents an array of classfile annotation arguments */ - case class ArrayAnnotArg(args: Array[ClassfileAnnotArg]) - extends ClassfileAnnotArg { - override def toString = args.mkString("[", ", ", "]") - } - - object ArrayAnnotArg extends ArrayAnnotArgExtractor - - /** A specific annotation argument that encodes an array of bytes as an array of `Long`. The type of the argument - * declared in the annotation must be `String`. This specialised class is used to encode scala signatures for - * reasons of efficiency, both in term of class-file size and in term of compiler performance. */ - case class ScalaSigBytes(bytes: Array[Byte]) extends ClassfileAnnotArg { - override def toString = (bytes map { byte => (byte & 0xff).toHexString }).mkString("[ ", " ", " ]") - lazy val encodedBytes = - reflect.generic.ByteCodecs.encode(bytes) - def isLong: Boolean = (encodedBytes.length > 65535) - def sigAnnot: Type = - if (this.isLong) - definitions.ScalaLongSignatureAnnotation.tpe - else - definitions.ScalaSignatureAnnotation.tpe - } - - /** Represents a nested classfile annotation */ - case class NestedAnnotArg(annInfo: AnnotationInfo) - extends ClassfileAnnotArg { - // The nested annotation should not have any Scala annotation arguments - assert(annInfo.args.isEmpty, annInfo.args) - override def toString = annInfo.toString - } - - object NestedAnnotArg extends NestedAnnotArgExtractor - - class AnnotationInfoBase - - /** <p> - * Typed information about an annotation. It can be attached to - * either a symbol or an annotated type. - * </p> - * <p> - * Annotations are written to the classfile as java annotations - * if <code>atp</code> conforms to <code>ClassfileAnnotation</code> - * (the classfile parser adds this interface to any Java annotation - * class). - * </p> - * <p> - * Annotations are pickled (written to scala symtab attribute - * in the classfile) if <code>atp</code> inherits form - * <code>StaticAnnotation</code>. - * </p> - * <p> - * <code>args</code> stores arguments to Scala annotations, - * represented as typed trees. Note that these trees are not - * transformed by any phases following the type-checker. - * </p> - * <p> - * <code>assocs</code> stores arguments to classfile annotations - * as name-value pairs. - * </p> - */ - case class AnnotationInfo(atp: Type, args: List[Tree], - assocs: List[(Name, ClassfileAnnotArg)]) - extends AnnotationInfoBase { - - // Classfile annot: args empty. Scala annot: assocs empty. - assert(args.isEmpty || assocs.isEmpty) - - private var rawpos: Position = NoPosition - def pos = rawpos - def setPos(pos: Position): this.type = { - rawpos = pos - this - } - - lazy val isTrivial: Boolean = atp.isTrivial && !(args exists (_.exists(_.isInstanceOf[This]))) // see annotationArgRewriter - - override def toString: String = atp + - (if (!args.isEmpty) args.mkString("(", ", ", ")") else "") + - (if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "") - - /** Check whether the type or any of the arguments are erroneous */ - def isErroneous = atp.isErroneous || args.exists(_.isErroneous) - - /** Check whether any of the arguments mention a symbol */ - def refsSymbol(sym: Symbol) = - args.exists(_.exists(_.symbol == sym)) - - /** Change all ident's with Symbol "from" to instead use symbol "to" */ - def substIdentSyms(from: Symbol, to: Symbol) = { - val subs = new TreeSymSubstituter(List(from), List(to)) - AnnotationInfo(atp, args.map(subs(_)), assocs).setPos(pos) - } - - // !!! when annotation arguments are not literal strings, but any sort of - // assembly of strings, there is a fair chance they will turn up here not as - // Literal(const) but some arbitrary AST. - def stringArg(index: Int): Option[String] = if(args.size > index) Some(args(index) match { - case Literal(const) => const.stringValue - case x => x.toString // should not be necessary, but better than silently ignoring an issue - }) else None - - def intArg(index: Int): Option[Int] = if(args.size > index) Some(args(index)) collect { - case Literal(Constant(x: Int)) => x - } else None - } - - object AnnotationInfo extends AnnotationInfoExtractor - - lazy val classfileAnnotArgManifest: ClassManifest[ClassfileAnnotArg] = - reflect.ClassManifest.classType(classOf[ClassfileAnnotArg]) - - /** Symbol annotations parsed in Namer (typeCompleter of - * definitions) have to be lazy (#1782) - */ - case class LazyAnnotationInfo(annot: () => AnnotationInfo) - extends AnnotationInfoBase -} diff --git a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala index c3dd5f4da3..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala +++ b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala @@ -1,251 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ -package scala.tools.nsc -package symtab - -// todo implement in terms of BitSet -import scala.collection.mutable.{ListBuffer, BitSet} -import math.max -import util.Statistics._ - -/** A base type sequence (BaseTypeSeq) is an ordered sequence spanning all the base types - * of a type. It characterized by the following two laws: - * - * (1) Each element of `tp.baseTypeSeq' is a basetype of `tp' - * (2) For each basetype `bt1' of `tp' there is an element `bt' in `tp.baseTypeSeq' such that - * - * bt.typeSymbol = bt1.typeSymbol - * bt <: bt1 - * - * (3) The type symbols of different elements are different. - * - * Elements in the sequence are ordered by Symbol.isLess. - * @note base type sequences were called closures up to 2.7.1. The name has been changed - * to avoid confusion with function closures. - */ -trait BaseTypeSeqs { - this: SymbolTable => - import definitions._ - - class BaseTypeSeq(parents: List[Type], elems: Array[Type]) { - self => - incCounter(baseTypeSeqCount) - incCounter(baseTypeSeqLenTotal, elems.length) - - /** The number of types in the sequence */ - def length: Int = elems.length - - // #3676 shows why we can't store NoType in elems to mark cycles - // (while NoType is in there to indicate a cycle in this BTS, during the execution of - // the mergePrefixAndArgs below, the elems get copied without the pending map, - // so that NoType's are seen instead of the original type --> spurious compile error) - val pending = new BitSet(length) - - /** The type at i'th position in this sequence; lazy types are returned evaluated. */ - def apply(i: Int): Type = - if(pending contains i) { - pending.clear() - throw CyclicInheritance - } else - elems(i) match { - case rtp @ RefinedType(variants, decls) => - // can't assert decls.isEmpty; see t0764 - //if (!decls.isEmpty) assert(false, "computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j)) - //Console.println("compute closure of "+this+" => glb("+variants+")") - pending += i - try { - mergePrefixAndArgs(variants, -1, lubDepth(variants)) match { - case Some(tp0) => - pending(i) = false - elems(i) = tp0 - tp0 - case None => - typeError( - "no common type instance of base types "+(variants mkString ", and ")+" exists.") - } - } catch { - case CyclicInheritance => - typeError( - "computing the common type instance of base types "+(variants mkString ", and ")+" leads to a cycle.") - } - case tp => - tp - } - - def rawElem(i: Int) = elems(i) - - /** The type symbol of the type at i'th position in this sequence; - * no evaluation needed. - */ - def typeSymbol(i: Int): Symbol = { - elems(i) match { - case RefinedType(v :: vs, _) => v.typeSymbol - case tp => tp.typeSymbol - } - } - - /** Return all evaluated types in this sequence as a list */ - def toList: List[Type] = elems.toList - - protected def copy(head: Type, offset: Int): BaseTypeSeq = { - val arr = new Array[Type](elems.length + offset) - compat.Platform.arraycopy(elems, 0, arr, offset, elems.length) - arr(0) = head - new BaseTypeSeq(parents, arr) - } - - /** Compute new base type sequence with `tp' prepended to this sequence */ - def prepend(tp: Type): BaseTypeSeq = copy(tp, 1) - - /** Compute new base type sequence with `tp' replacing the head of this sequence */ - def updateHead(tp: Type): BaseTypeSeq = copy(tp, 0) - - /** Compute new base type sequence where every element is mapped - * with function `f'. Lazy types are mapped but not evaluated */ - def map(f: Type => Type): BaseTypeSeq = { - // inlined `elems map f' for performance - val len = length - var arr = new Array[Type](len) - var i = 0 - while (i < len) { - arr(i) = f(elems(i)) - i += 1 - } - new BaseTypeSeq(parents, arr) - } - - def lateMap(f: Type => Type): BaseTypeSeq = new BaseTypeSeq(parents map f, elems) { - override def apply(i: Int) = f(self.apply(i)) - override def rawElem(i: Int) = f(self.rawElem(i)) - override def typeSymbol(i: Int) = self.typeSymbol(i) - override def toList = self.toList map f - override protected def copy(head: Type, offset: Int) = (self map f).copy(head, offset) - override def map(g: Type => Type) = lateMap(g) - override def lateMap(g: Type => Type) = self.lateMap(x => g(f(x))) - override def exists(p: Type => Boolean) = elems exists (x => p(f(x))) - override protected def maxDepthOfElems: Int = elems map (x => maxDpth(f(x))) max - override def toString = elems.mkString("MBTS(", ",", ")") - } - - def exists(p: Type => Boolean): Boolean = elems exists p - - lazy val maxDepth: Int = maxDepthOfElems - - protected def maxDepthOfElems = { - var d = 0 - for (i <- 0 until length) d = max(d, maxDpth(elems(i))) - d - } - - /** The maximum depth of type `tp' */ - protected def maxDpth(tp: Type): Int = tp match { - case TypeRef(pre, sym, args) => - max(maxDpth(pre), maxDpth(args) + 1) - case RefinedType(parents, decls) => - max(maxDpth(parents), maxDpth(decls.toList.map(_.info)) + 1) - case TypeBounds(lo, hi) => - max(maxDpth(lo), maxDpth(hi)) - case MethodType(paramtypes, result) => - maxDpth(result) - case NullaryMethodType(result) => - maxDpth(result) - case PolyType(tparams, result) => - max(maxDpth(result), maxDpth(tparams map (_.info)) + 1) - case ExistentialType(tparams, result) => - max(maxDpth(result), maxDpth(tparams map (_.info)) + 1) - case _ => - 1 - } - - /** The maximum depth of all types `tps' */ - private def maxDpth(tps: Seq[Type]): Int = { - var d = 0 - for (tp <- tps) d = max(d, maxDpth(tp)) - d - } - - override def toString = elems.mkString("BTS(", ",", ")") - - private def typeError(msg: String): Nothing = - throw new TypeError( - "the type intersection "+(parents mkString " with ")+" is malformed"+ - "\n --- because ---\n"+msg) - } - - /** A merker object for a base type sequence that's no yet computed. - * used to catch inheritance cycles - */ - val undetBaseTypeSeq: BaseTypeSeq = new BaseTypeSeq(List(), Array()) - - /** Create a base type sequence consisting of a single type */ - def baseTypeSingletonSeq(tp: Type): BaseTypeSeq = new BaseTypeSeq(List(), Array(tp)) - - /** Create the base type sequence of a compound type wuth given tp.parents */ - def compoundBaseTypeSeq(tp: Type): BaseTypeSeq = { - val tsym = tp.typeSymbol - val parents = tp.parents -// Console.println("computing baseTypeSeq of " + tsym.tpe + " " + parents)//DEBUG - val buf = new ListBuffer[Type] - buf += tsym.tpe - var btsSize = 1 - if (parents.nonEmpty) { - val nparents = parents.length - val pbtss = new Array[BaseTypeSeq](nparents) - val index = new Array[Int](nparents) - var i = 0 - for (p <- parents) { - pbtss(i) = - if (p.baseTypeSeq eq undetBaseTypeSeq) AnyClass.info.baseTypeSeq - else p.baseTypeSeq - index(i) = 0 - i += 1 - } - def nextTypeSymbol(i: Int): Symbol = { - val j = index(i) - val pbts = pbtss(i) - if (j < pbts.length) pbts.typeSymbol(j) else AnyClass - } - def nextRawElem(i: Int): Type = { - val j = index(i) - val pbts = pbtss(i) - if (j < pbts.length) pbts.rawElem(j) else AnyClass.tpe - } - var minSym: Symbol = NoSymbol - while (minSym != AnyClass) { - minSym = nextTypeSymbol(0) - i = 1 - while (i < nparents) { - val nextSym = nextTypeSymbol(i) - if (nextSym isLess minSym) - minSym = nextSym - i += 1 - } - var minTypes: List[Type] = List() - i = 0 - while (i < nparents) { - if (nextTypeSymbol(i) == minSym) { - nextRawElem(i) match { - case RefinedType(variants, decls) => - for (tp <- variants) - if (!(minTypes exists (tp =:=))) minTypes = tp :: minTypes - case tp => - if (!(minTypes exists (tp =:=))) minTypes = tp :: minTypes - } - index(i) = index(i) + 1 - } - i += 1 - } - buf += intersectionType(minTypes) - btsSize += 1 - } - } - val elems = new Array[Type](btsSize) - buf.copyToArray(elems, 0) -// Console.println("computed baseTypeSeq of " + tsym.tpe + " " + parents + ": "+elems.toString)//DEBUG - new BaseTypeSeq(parents, elems) - } - - val CyclicInheritance = new Throwable -} diff --git a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala index b024d550b7..060b3c5ce4 100644 --- a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala @@ -6,7 +6,6 @@ package scala.tools.nsc package symtab -import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.util.BatchSourceFile /** A subclass of SymbolLoaders that implements browsing behavior. diff --git a/src/compiler/scala/tools/nsc/symtab/Caches.scala b/src/compiler/scala/tools/nsc/symtab/Caches.scala index 10d7500f09..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/Caches.scala +++ b/src/compiler/scala/tools/nsc/symtab/Caches.scala @@ -1,103 +0,0 @@ -/* NSC -- new scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package symtab - -import scala.collection.{ mutable, immutable } - -/** A cache for some entity whose validity depends on a monotonically - * increasing sequence number. - */ -abstract class SequencedCache[T >: Null] { - def zero: Int - def sequenceId: Int - def calculate(): T - - /** If sequence numbers differ, this condition is consulted before - * updating the cached value. - */ - def isCacheValid: Boolean - - /** Public so accesses can be inlined. */ - @inline var cachedId: Int = 0 - @inline var cachedValue: T = _ - - /** Puts cache back in uninitialized state. */ - @inline final def clear() = { - cachedId = zero - cachedValue = null - } - /** Resets the sequence id without touching the cached value. */ - @inline final def reset() = { - cachedId = zero - } - - final def get(): T = { - if (cachedValue == null) { - cachedValue = calculate() - cachedId = sequenceId - } - else if (cachedId != sequenceId) { - if (!isCacheValid) - cachedValue = calculate() - - cachedId = sequenceId - } - cachedValue - } -} - -trait Caches { - self: SymbolTable => - - final def isValid(period: Period): Boolean = - period != 0 && runId(period) == currentRunId && { - val pid = phaseId(period) - if (phase.id > pid) infoTransformers.nextFrom(pid).pid >= phase.id - else infoTransformers.nextFrom(phase.id).pid >= pid - } - - final def isValidForBaseClasses(period: Period): Boolean = { - def noChangeInBaseClasses(it: InfoTransformer, limit: Phase#Id): Boolean = ( - it.pid >= limit || - !it.changesBaseClasses && noChangeInBaseClasses(it.next, limit) - ); - period != 0 && runId(period) == currentRunId && { - val pid = phaseId(period) - if (phase.id > pid) noChangeInBaseClasses(infoTransformers.nextFrom(pid), phase.id) - else noChangeInBaseClasses(infoTransformers.nextFrom(phase.id), pid) - } - } - - abstract class PeriodCache[T >: Null] extends SequencedCache[T] { - final val zero = NoPeriod - @inline final def sequenceId = currentPeriod - } - - abstract class ListOfTypesCache extends PeriodCache[List[Type]] { - @inline final def isCacheValid = isValidForBaseClasses(cachedId) - } - abstract class ListOfSymbolsCache extends PeriodCache[List[Symbol]] { - @inline final def isCacheValid = isValidForBaseClasses(cachedId) - } - abstract class BaseTypeSeqCache extends PeriodCache[BaseTypeSeq] { - @inline final def isCacheValid = isValidForBaseClasses(cachedId) - } - abstract class TypeCache extends PeriodCache[Type] { - @inline final def isCacheValid = isValid(cachedId) - } - abstract class TypeCacheForRunId extends SequencedCache[Type] { - final val zero = NoRunId - @inline final def sequenceId = currentRunId - @inline final override def isCacheValid = false - } - object TypeCache { - def apply(body: => Type): TypeCache = new TypeCache { - @inline final def calculate() = body - } - } -} - diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala index e74de01016..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/Flags.scala +++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala @@ -1,220 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package symtab - -// Flags at each index of a flags Long. Those marked with /M are used in -// Parsers/JavaParsers and therefore definitely appear on Modifiers; but the -// absence of /M on the other flags does not imply they aren't. -// -// Generated by mkFlagsTable() at Mon Oct 11 10:01:09 PDT 2010 -// -// 0: PROTECTED/M -// 1: OVERRIDE/M -// 2: PRIVATE/M -// 3: ABSTRACT/M -// 4: DEFERRED/M -// 5: FINAL/M -// 6: METHOD -// 7: INTERFACE/M -// 8: MODULE -// 9: IMPLICIT/M -// 10: SEALED/M -// 11: CASE/M -// 12: MUTABLE/M -// 13: PARAM/M -// 14: PACKAGE -// 15: -// 16: BYNAMEPARAM/M CAPTURED COVARIANT/M -// 17: CONTRAVARIANT/M INCONSTRUCTOR LABEL -// 18: ABSOVERRIDE/M -// 19: LOCAL/M -// 20: JAVA/M -// 21: SYNTHETIC -// 22: STABLE -// 23: STATIC/M -// 24: CASEACCESSOR/M -// 25: DEFAULTPARAM/M TRAIT/M -// 26: BRIDGE -// 27: ACCESSOR -// 28: SUPERACCESSOR -// 29: PARAMACCESSOR/M -// 30: MODULEVAR -// 31: LAZY/M -// 32: IS_ERROR -// 33: OVERLOADED -// 34: LIFTED -// 35: EXISTENTIAL MIXEDIN -// 36: EXPANDEDNAME -// 37: IMPLCLASS PRESUPER/M -// 38: TRANS_FLAG -// 39: LOCKED -// 40: SPECIALIZED -// 41: DEFAULTINIT/M -// 42: VBRIDGE -// 43: VARARGS -// 44: -// 45: -// 46: -// 47: -// 48: -// 49: latePRIVATE -// 50: lateABSTRACT -// 51: lateDEFERRED -// 52: lateFINAL -// 53: lateMETHOD -// 54: lateINTERFACE -// 55: lateMODULE -// 56: notPROTECTED -// 57: notOVERRIDE -// 58: notPRIVATE -// 59: notABSTRACT -// 60: notDEFERRED -// 61: notFINAL -// 62: notMETHOD -// 63: -class Flags extends reflect.generic.Flags { - - final val InitialFlags = 0x0001FFFFFFFFFFFFL // flags that are enabled from phase 1. - final val LateFlags = 0x00FE000000000000L // flags that override flags in 0x1FC. - final val AntiFlags = 0x7F00000000000000L // flags that cancel flags in 0x07F - final val LateShift = 47L - final val AntiShift = 56L - - // late flags (set by a transformer phase) - final val latePRIVATE = (PRIVATE: Long) << LateShift - final val lateABSTRACT = (ABSTRACT: Long) << LateShift - final val lateDEFERRED = (DEFERRED: Long) << LateShift - final val lateINTERFACE = (INTERFACE: Long) << LateShift - final val lateMODULE = (MODULE: Long) << LateShift - final val lateFINAL = (FINAL: Long) << LateShift - final val lateMETHOD = (METHOD: Long) << LateShift - - final val notFINAL = (FINAL: Long) << AntiShift - final val notPRIVATE = (PRIVATE: Long) << AntiShift - final val notDEFERRED = (DEFERRED: Long) << AntiShift - final val notPROTECTED = (PROTECTED: Long) << AntiShift - final val notABSTRACT = (ABSTRACT: Long) << AntiShift - final val notOVERRIDE = (OVERRIDE: Long) << AntiShift - final val notMETHOD = (METHOD: Long) << AntiShift - - final val notFlagMap = Map[Int, Long]( - FINAL -> notFINAL, - PRIVATE -> notPRIVATE, - DEFERRED -> notDEFERRED, - PROTECTED -> notPROTECTED, - ABSTRACT -> notABSTRACT, - OVERRIDE -> notOVERRIDE, - METHOD -> notMETHOD - ) - - // masks - /** These flags can be set when class or module symbol is first created. */ - final val TopLevelCreationFlags: Long = - MODULE | PACKAGE | FINAL | JAVA - - /** These modifiers can be set explicitly in source programs. */ - final val ExplicitFlags: Long = - PRIVATE | PROTECTED | ABSTRACT | FINAL | SEALED | - OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE | LAZY - - /** These modifiers appear in TreePrinter output. */ - final val PrintableFlags: Long = - ExplicitFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | - ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | BRIDGE | STATIC | VBRIDGE | SPECIALIZED - - /** The two bridge flags */ - final val BRIDGES = BRIDGE | VBRIDGE - - final val FieldFlags: Long = - MUTABLE | CASEACCESSOR | PARAMACCESSOR | STATIC | FINAL | PRESUPER | LAZY - - final val AccessFlags: Long = PRIVATE | PROTECTED | LOCAL - final val VarianceFlags = COVARIANT | CONTRAVARIANT - final val ConstrFlags: Long = JAVA - - /** Module flags inherited by their module-class */ - final val ModuleToClassFlags: Long = AccessFlags | MODULE | PACKAGE | CASE | SYNTHETIC | JAVA - - def getterFlags(fieldFlags: Long): Long = ACCESSOR + ( - if ((fieldFlags & MUTABLE) != 0) fieldFlags & ~MUTABLE & ~PRESUPER - else fieldFlags & ~PRESUPER | STABLE - ) - - def setterFlags(fieldFlags: Long): Long = - getterFlags(fieldFlags) & ~STABLE & ~CASEACCESSOR - - // Generated by mkFlagToStringMethod() at Mon Oct 11 10:12:36 PDT 2010 - @annotation.switch override def flagToString(flag: Long): String = flag match { - case PROTECTED => "protected" // (1L << 0) - case OVERRIDE => "override" // (1L << 1) - case PRIVATE => "private" // (1L << 2) - case ABSTRACT => "abstract" // (1L << 3) - case DEFERRED => "<deferred>" // (1L << 4) - case FINAL => "final" // (1L << 5) - case METHOD => "<method>" // (1L << 6) - case INTERFACE => "<interface>" // (1L << 7) - case MODULE => "<module>" // (1L << 8) - case IMPLICIT => "implicit" // (1L << 9) - case SEALED => "sealed" // (1L << 10) - case CASE => "case" // (1L << 11) - case MUTABLE => "<mutable>" // (1L << 12) - case PARAM => "<param>" // (1L << 13) - case PACKAGE => "<package>" // (1L << 14) - case 0x8000L => "" // (1L << 15) - case BYNAMEPARAM => "<bynameparam/captured/covariant>" // (1L << 16) - case CONTRAVARIANT => "<contravariant/inconstructor/label>" // (1L << 17) - case ABSOVERRIDE => "absoverride" // (1L << 18) - case LOCAL => "<local>" // (1L << 19) - case JAVA => "<java>" // (1L << 20) - case SYNTHETIC => "<synthetic>" // (1L << 21) - case STABLE => "<stable>" // (1L << 22) - case STATIC => "<static>" // (1L << 23) - case CASEACCESSOR => "<caseaccessor>" // (1L << 24) - case DEFAULTPARAM => "<defaultparam/trait>" // (1L << 25) - case BRIDGE => "<bridge>" // (1L << 26) - case ACCESSOR => "<accessor>" // (1L << 27) - case SUPERACCESSOR => "<superaccessor>" // (1L << 28) - case PARAMACCESSOR => "<paramaccessor>" // (1L << 29) - case MODULEVAR => "<modulevar>" // (1L << 30) - case LAZY => "lazy" // (1L << 31) - case IS_ERROR => "<is_error>" // (1L << 32) - case OVERLOADED => "<overloaded>" // (1L << 33) - case LIFTED => "<lifted>" // (1L << 34) - case EXISTENTIAL => "<existential/mixedin>" // (1L << 35) - case EXPANDEDNAME => "<expandedname>" // (1L << 36) - case IMPLCLASS => "<implclass/presuper>" // (1L << 37) - case TRANS_FLAG => "<trans_flag>" // (1L << 38) - case LOCKED => "<locked>" // (1L << 39) - case SPECIALIZED => "<specialized>" // (1L << 40) - case DEFAULTINIT => "<defaultinit>" // (1L << 41) - case VBRIDGE => "<vbridge>" // (1L << 42) - case VARARGS => "<varargs>" // (1L << 43) - case 0x100000000000L => "" // (1L << 44) - case 0x200000000000L => "" // (1L << 45) - case 0x400000000000L => "" // (1L << 46) - case 0x800000000000L => "" // (1L << 47) - case 0x1000000000000L => "" // (1L << 48) - case `latePRIVATE` => "<lateprivate>" // (1L << 49) - case `lateABSTRACT` => "<lateabstract>" // (1L << 50) - case `lateDEFERRED` => "<latedeferred>" // (1L << 51) - case `lateFINAL` => "<latefinal>" // (1L << 52) - case `lateMETHOD` => "<latemethod>" // (1L << 53) - case `lateINTERFACE` => "<lateinterface>" // (1L << 54) - case `lateMODULE` => "<latemodule>" // (1L << 55) - case `notPROTECTED` => "<notprotected>" // (1L << 56) - case `notOVERRIDE` => "<notoverride>" // (1L << 57) - case `notPRIVATE` => "<notprivate>" // (1L << 58) - case `notABSTRACT` => "<notabstract>" // (1L << 59) - case `notDEFERRED` => "<notdeferred>" // (1L << 60) - case `notFINAL` => "<notfinal>" // (1L << 61) - case `notMETHOD` => "<notmethod>" // (1L << 62) - case 0x8000000000000000L => "" // (1L << 63) - case _ => "" - } -} - -object Flags extends Flags { } diff --git a/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala b/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala index 69896c634f..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala +++ b/src/compiler/scala/tools/nsc/symtab/InfoTransformers.scala @@ -1,47 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package symtab - -trait InfoTransformers { - self: SymbolTable => - - abstract class InfoTransformer { - var prev: InfoTransformer = this - var next: InfoTransformer = this - - val pid: Phase#Id - val changesBaseClasses: Boolean - def transform(sym: Symbol, tpe: Type): Type - - def insert(that: InfoTransformer) { - assert(this.pid != that.pid) - if (that.pid < this.pid) { - prev insert that - } else if (next.pid <= that.pid && next.pid != NoPhase.id) { - next insert that - } else { - that.next = next - that.prev = this - next.prev = that - this.next = that - } - } - - /** The InfoTransformer whose (pid == from). - * If no such exists, the InfoTransformer with the next - * higher pid. - */ - def nextFrom(from: Phase#Id): InfoTransformer = - if (from == this.pid) this - else if (from < this.pid) - if (prev.pid < from) this - else prev.nextFrom(from); - else if (next.pid == NoPhase.id) next - else next.nextFrom(from) - } -} - diff --git a/src/compiler/scala/tools/nsc/symtab/NameManglers.scala b/src/compiler/scala/tools/nsc/symtab/NameManglers.scala index 5ef0da8282..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/NameManglers.scala +++ b/src/compiler/scala/tools/nsc/symtab/NameManglers.scala @@ -1,172 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package symtab - -import java.security.MessageDigest -import scala.io.Codec -import util.Chars.isOperatorPart - -/** A trait to encapsulate name mangling. It's intended for the - * values and methods involved in assembling names out of other names, - * and not for simple synthetically named locals. - */ -trait NameManglers { - self: SymbolTable => - - trait NameManglingCommon { - self: CompilerCommonNames => - - def flattenedName(segments: Name*): NameType = compactedString(segments mkString "$") - - /** - * COMPACTIFY - * - * The hashed name has the form (prefix + marker + md5 + marker + suffix), where - * - prefix/suffix.length = MaxNameLength / 4 - * - md5.length = 32 - * - * We obtain the formula: - * - * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + 6 - * - * (+6 for ".class"). MaxNameLength can therefore be computed as follows: - */ - private final val marker = "$$$$" - private final val MaxNameLength = math.min( - settings.maxClassfileName.value - 6, - 2 * (settings.maxClassfileName.value - 6 - 2*marker.length - 32) - ) - private lazy val md5 = MessageDigest.getInstance("MD5") - private def toMD5(s: String, edge: Int) = { - val prefix = s take edge - val suffix = s takeRight edge - - val cs = s.toArray - val bytes = Codec toUTF8 cs - md5 update bytes - val md5chars = md5.digest() map (b => (b & 0xFF).toHexString) mkString - - prefix + marker + md5chars + marker + suffix - } - private def compactedString(s: String) = - if (s.length <= MaxNameLength) s - else toMD5(s, MaxNameLength / 4) - } - - trait TypeNameMangling extends NameManglingCommon { - self: tpnme.type => - - } - - trait TermNameMangling extends NameManglingCommon { - self: nme.type => - - val IMPL_CLASS_SUFFIX = "$class" - val SINGLETON_SUFFIX = ".type" - val LOCALDUMMY_PREFIX = "<local " // owner of local blocks - val PROTECTED_PREFIX = "protected$" - val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set" - val SELECTOR_DUMMY = "<unapply-selector>" - val SETTER_SUFFIX = encode("_=") - val SUPER_PREFIX_STRING = "super$" - val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$" - - def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR - def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX - /** !!! Foo$class$1 is an implClassName, I think. */ - def isImplClassName(name: Name) = name endsWith IMPL_CLASS_SUFFIX - def isLocalDummyName(name: Name) = name startsWith LOCALDUMMY_PREFIX - def isLocalName(name: Name) = name endsWith LOCAL_SUFFIX_STRING - def isLoopHeaderLabel(name: Name) = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) - def isProtectedAccessorName(name: Name) = name startsWith PROTECTED_PREFIX - def isReplWrapperName(name: Name) = name containsName INTERPRETER_IMPORT_WRAPPER - def isSetterName(name: Name) = name endsWith SETTER_SUFFIX - def isTraitSetterName(name: Name) = isSetterName(name) && (name containsName TRAIT_SETTER_SEPARATOR_STRING) - def isSingletonName(name: Name) = name endsWith SINGLETON_SUFFIX - - def isOpAssignmentName(name: Name) = name match { - case raw.NE | raw.LE | raw.GE | EMPTY => false - case _ => - name.endChar == '=' && name.startChar != '=' && isOperatorPart(name.startChar) - } - - /** The expanded setter name of `name' relative to this class `base` - */ - def expandedSetterName(name: TermName, base: Symbol): TermName = - expandedName(name, base, separator = TRAIT_SETTER_SEPARATOR_STRING) - - /** If `name' is an expandedName name, the original name. - * Otherwise `name' itself. - */ - def originalName(name: Name): Name = { - var i = name.length - while (i >= 2 && !(name(i - 1) == '$' && name(i - 2) == '$')) i -= 1 - if (i >= 2) { - while (i >= 3 && name(i - 3) == '$') i -= 1 - name.subName(i, name.length) - } else name - } - - /** Return the original name and the types on which this name - * is specialized. For example, - * {{{ - * splitSpecializedName("foo$mIcD$sp") == ('foo', "I", "D") - * }}} - * `foo$mIcD$sp` is the name of a method specialized on two type - * parameters, the first one belonging to the method itself, on Int, - * and another one belonging to the enclosing class, on Double. - */ - def splitSpecializedName(name: Name): (Name, String, String) = - if (name.endsWith("$sp")) { - val name1 = name stripEnd "$sp" - val idxC = name1 lastIndexOf 'c' - val idxM = name1 lastIndexOf 'm' - - (name1.subName(0, idxM - 1), - name1.subName(idxC + 1, name1.length).toString, - name1.subName(idxM + 1, idxC).toString) - } else - (name, "", "") - - def getterName(name: TermName): TermName = if (isLocalName(name)) localToGetter(name) else name - def getterToLocal(name: TermName): TermName = name.toTermName append LOCAL_SUFFIX_STRING - def getterToSetter(name: TermName): TermName = name.toTermName append SETTER_SUFFIX - def localToGetter(name: TermName): TermName = name stripEnd LOCAL_SUFFIX_STRING toTermName - - def setterToGetter(name: TermName): TermName = { - val p = name.pos(TRAIT_SETTER_SEPARATOR_STRING) - if (p < name.length) - setterToGetter(name.subName(p + TRAIT_SETTER_SEPARATOR_STRING.length, name.length)) - else - name stripEnd SETTER_SUFFIX toTermName - } - - def defaultGetterName(name: Name, pos: Int): TermName = { - val prefix = if (isConstructorName(name)) "init" else name - newTermName(prefix + DEFAULT_GETTER_STRING + pos) - } - def defaultGetterToMethod(name: Name): TermName = { - val p = name.pos(DEFAULT_GETTER_STRING) - if (p < name.length) name.subName(0, p) - else name - } - - def dropSingletonName(name: Name): TypeName = name stripEnd SINGLETON_SUFFIX toTypeName - def singletonName(name: Name): TypeName = name append SINGLETON_SUFFIX toTypeName - def implClassName(name: Name): TypeName = name append IMPL_CLASS_SUFFIX toTypeName - def interfaceName(implname: Name): TypeName = implname stripEnd IMPL_CLASS_SUFFIX toTypeName - def localDummyName(clazz: Symbol): TermName = newTermName(LOCALDUMMY_PREFIX + clazz.name + ">") - def productAccessorName(i: Int): TermName = newTermName("_" + i) - def superName(name: Name): TermName = newTermName(SUPER_PREFIX_STRING + name) - - /** The name of an accessor for protected symbols. */ - def protName(name: Name): TermName = newTermName(PROTECTED_PREFIX + name) - - /** The name of a setter for protected symbols. Used for inherited Java fields. */ - def protSetterName(name: Name): TermName = newTermName(PROTECTED_SET_PREFIX + name) - } -} diff --git a/src/compiler/scala/tools/nsc/symtab/Names.scala b/src/compiler/scala/tools/nsc/symtab/Names.scala index 7eccb9a49f..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/Names.scala +++ b/src/compiler/scala/tools/nsc/symtab/Names.scala @@ -1,429 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package symtab - -import scala.reflect.NameTransformer -import scala.io.Codec -import java.security.MessageDigest - -/** The class Names ... - * - * @author Martin Odersky - * @version 1.0, 05/02/2005 - */ -trait Names extends reflect.generic.Names { - -// Operations ------------------------------------------------------------- - - private final val HASH_SIZE = 0x8000 - private final val HASH_MASK = 0x7FFF - private final val NAME_SIZE = 0x20000 - - final val nameDebug = false - - /** memory to store all names sequentially - */ - var chrs: Array[Char] = new Array[Char](NAME_SIZE) - private var nc = 0 - - /** hashtable for finding term names quickly - */ - private val termHashtable = new Array[TermName](HASH_SIZE) - - /** hashtable for finding type names quickly - */ - private val typeHashtable = new Array[TypeName](HASH_SIZE) - - /** the hashcode of a name - */ - private def hashValue(cs: Array[Char], offset: Int, len: Int): Int = - if (len > 0) - (len * (41 * 41 * 41) + - cs(offset) * (41 * 41) + - cs(offset + len - 1) * 41 + - cs(offset + (len >> 1))) - else 0; - - /** Is (the ASCII representation of) name at given index equal to - * cs[offset..offset+len-1]? - */ - private def equals(index: Int, cs: Array[Char], offset: Int, len: Int): Boolean = { - var i = 0 - while ((i < len) && (chrs(index + i) == cs(offset + i))) - i += 1; - i == len - } - - /** enter characters into chrs array - */ - private def enterChars(cs: Array[Char], offset: Int, len: Int) { - var i = 0 - while (i < len) { - if (nc + i == chrs.length) { - val newchrs = new Array[Char](chrs.length * 2) - compat.Platform.arraycopy(chrs, 0, newchrs, 0, chrs.length) - chrs = newchrs - } - chrs(nc + i) = cs(offset + i) - i += 1 - } - if (len == 0) nc += 1 - else nc = nc + len - } - - /** Create a term name from the characters in cs[offset..offset+len-1]. - */ - def newTermName(cs: Array[Char], offset: Int, len: Int): TermName = { - val h = hashValue(cs, offset, len) & HASH_MASK - var n = termHashtable(h) - while ((n ne null) && (n.length != len || !equals(n.start, cs, offset, len))) - n = n.next; - if (n eq null) { - n = new TermName(nc, len, h) - enterChars(cs, offset, len) - } - n - } - - /** create a term name from string - */ - def newTermName(s: String): TermName = - newTermName(s.toCharArray(), 0, s.length()) - - /** Create a term name from the UTF8 encoded bytes in bs[offset..offset+len-1]. - */ - def newTermName(bs: Array[Byte], offset: Int, len: Int): TermName = - newTermName(Codec fromUTF8 bs.slice(offset, offset + len) mkString) - - /** Create a type name from the characters in cs[offset..offset+len-1]. - */ - def newTypeName(cs: Array[Char], offset: Int, len: Int): TypeName = - newTermName(cs, offset, len).toTypeName - - /** Create a type name from string - */ - def newTypeName(s: String): TypeName = - newTermName(s).toTypeName - - /** Create a type name from the UTF8 encoded bytes in bs[offset..offset+len-1]. - */ - def newTypeName(bs: Array[Byte], offset: Int, len: Int): TypeName = - newTermName(bs, offset, len).toTypeName - - def mkTermName(name: Name): TermName = name.toTermName - def mkTypeName(name: Name): TypeName = name.toTypeName - def isTermName(name: Name): Boolean = name.isTermName - def isTypeName(name: Name): Boolean = name.isTypeName - - def nameChars: Array[Char] = chrs - @deprecated("", "2.9.0") def view(s: String): TermName = newTermName(s) - -// Classes ---------------------------------------------------------------------- - - /** The name class. */ - sealed abstract class Name(protected val index: Int, protected val len: Int) extends Function1[Int, Char] { - /** Index into name table */ - def start: Int = index - - /** next name in the same hash bucket - */ - def next: Name - - /** return the length of this name - */ - final def length: Int = len - final def isEmpty = length == 0 - final def nonEmpty = !isEmpty - - def isTermName: Boolean - def isTypeName: Boolean - def toTermName: TermName - def toTypeName: TypeName - def companionName: Name - def bothNames: List[Name] = List(toTermName, toTypeName) - - /** Copy bytes of this name to buffer cs, starting at position `offset`. - */ - final def copyChars(cs: Array[Char], offset: Int) = - compat.Platform.arraycopy(chrs, index, cs, offset, len) - - /** return the ascii representation of this name - */ - final def toChars: Array[Char] = { - val cs = new Array[Char](len) - copyChars(cs, 0) - cs - } - - /** return the string representation of this name - */ - final override def toString(): String = new String(chrs, index, len) - def debugString() = NameTransformer.decode(toString) + (if (isTypeName) "!" else "") - - /** Write to UTF8 representation of this name to given character array. - * Start copying to index `to'. Return index of next free byte in array. - * Array must have enough remaining space for all bytes - * (i.e. maximally 3*length bytes). - */ - final def copyUTF8(bs: Array[Byte], offset: Int): Int = { - val bytes = Codec toUTF8 chrs.slice(index, index + len) - compat.Platform.arraycopy(bytes, 0, bs, offset, bytes.length) - offset + bytes.length - } - - /** return the hash value of this name - */ - final override def hashCode(): Int = index - - // Presently disabled. - // override def equals(other: Any) = paranoidEquals(other) - private def paranoidEquals(other: Any): Boolean = { - val cmp = this eq other.asInstanceOf[AnyRef] - if (cmp || !nameDebug) - return cmp - - other match { - case x: String => - Console.println("Compared " + debugString + " and String '" + x + "'") - case x: Name => - if (this.isTermName != x.isTermName) { - val panic = this.toTermName == x.toTermName - Console.println("Compared '%s' and '%s', one term, one type.%s".format(this, x, - if (panic) " And they contain the same name string!" - else "" - )) - } - case _ => - } - false - } - - /** return the i'th Char of this name - */ - final def apply(i: Int): Char = chrs(index + i) - - /** return the index of first occurrence of char c in this name, length if not found */ - final def pos(c: Char): Int = pos(c, 0) - - /** return the index of first occurrence of char c in this name, length if not found */ - final def pos(s: String): Int = pos(s, 0) - - /** return the index of the first occurrence of character c in - * this name from start, length if not found. - * - * @param c the character - * @param start ... - * @return the index of the first occurrence of c - */ - final def pos(c: Char, start: Int): Int = { - var i = start - while (i < len && chrs(index + i) != c) i += 1 - i - } - - /** return the index of the first occurrence of nonempty string s - * in this name from start, length if not found. - * - * @param s the string - * @param start ... - * @return the index of the first occurrence of s - */ - final def pos(s: String, start: Int): Int = { - var i = pos(s.charAt(0), start) - while (i + s.length() <= len) { - var j = 1 - while (s.charAt(j) == chrs(index + i + j)) { - j += 1 - if (j == s.length()) return i - } - i = pos(s.charAt(0), i + 1) - } - len - } - - /** return the index of last occurrence of char c in this - * name, -1 if not found. - * - * @param c the character - * @return the index of the last occurrence of c - */ - final def lastPos(c: Char): Int = lastPos(c, len - 1) - - final def lastPos(s: String): Int = lastPos(s, len - s.length) - - /** return the index of the last occurrence of char c in this - * name from start, -1 if not found. - * - * @param c the character - * @param start ... - * @return the index of the last occurrence of c - */ - final def lastPos(c: Char, start: Int): Int = { - var i = start - while (i >= 0 && chrs(index + i) != c) i -= 1 - i - } - - /** return the index of the last occurrence of string s in this - * name from start, -1 if not found. - * - * @param s the string - * @param start ... - * @return the index of the last occurrence of s - */ - final def lastPos(s: String, start: Int): Int = { - var i = lastPos(s.charAt(0), start) - while (i >= 0) { - var j = 1; - while (s.charAt(j) == chrs(index + i + j)) { - j += 1 - if (j == s.length()) return i; - } - i = lastPos(s.charAt(0), i - 1) - } - -s.length() - } - - /** does this name start with prefix? - */ - final def startsWith(prefix: Name): Boolean = startsWith(prefix, 0) - - /** does this name start with prefix at given start index? - */ - final def startsWith(prefix: Name, start: Int): Boolean = { - var i = 0 - while (i < prefix.length && start + i < len && - chrs(index + start + i) == chrs(prefix.start + i)) - i += 1; - i == prefix.length - } - - /** does this name end with suffix? - */ - final def endsWith(suffix: Name): Boolean = endsWith(suffix, len) - - /** does this name end with suffix just before given end index? - */ - final def endsWith(suffix: Name, end: Int): Boolean = { - var i = 1 - while (i <= suffix.length && i <= end && - chrs(index + end - i) == chrs(suffix.start + suffix.length - i)) - i += 1; - i > suffix.length - } - - final def containsName(subname: String): Boolean = containsName(newTermName(subname)) - final def containsName(subname: Name): Boolean = { - var start = 0 - val last = len - subname.length - while (start <= last && !startsWith(subname, start)) start += 1 - start <= last - } - - /** Some thoroughly self-explanatory convenience functions. They - * assume that what they're being asked to do is known to be valid. - */ - final def startChar: Char = apply(0) - final def endChar: Char = apply(len - 1) - final def startsWith(char: Char): Boolean = len > 0 && startChar == char - final def startsWith(name: String): Boolean = startsWith(newTermName(name)) - final def endsWith(char: Char): Boolean = len > 0 && endChar == char - final def endsWith(name: String): Boolean = endsWith(newTermName(name)) - final def stripStart(prefix: Name): Name = subName(prefix.length, len) - final def stripStart(prefix: String): Name = subName(prefix.length, len) - final def stripEnd(suffix: Name): Name = subName(0, len - suffix.length) - final def stripEnd(suffix: String): Name = subName(0, len - suffix.length) - - def lastIndexOf(ch: Char) = toChars lastIndexOf ch - - /** Return the subname with characters from start to end-1. - */ - def subName(from: Int, to: Int): Name - - /** Replace all occurrences of `from` by `to` in - * name; result is always a term name. - */ - def replace(from: Char, to: Char): Name = { - val cs = new Array[Char](len) - var i = 0 - while (i < len) { - val ch = this(i) - cs(i) = if (ch == from) to else ch - i += 1 - } - newTermName(cs, 0, len) - } - - /** Replace operator symbols by corresponding $op_name. - */ - def encode: Name = { - val str = toString() - val res = NameTransformer.encode(str) - if (res == str) this - else if (isTypeName) newTypeName(res) - else newTermName(res) - } - - def append(suffix: String): Name - def append(suffix: Name): Name - - /** Replace $op_name by corresponding operator symbol. - */ - def decode: String = ( - NameTransformer.decode(toString()) + - (if (nameDebug && isTypeName) "!" else ""))//debug - - def isOperatorName: Boolean = decode != toString - def nameKind: String = if (isTypeName) "type" else "term" - def longString: String = nameKind + " " + NameTransformer.decode(toString) - } - - final class TermName(_index: Int, _len: Int, hash: Int) extends Name(_index, _len) { - var next: TermName = termHashtable(hash) - termHashtable(hash) = this - def isTermName: Boolean = true - def isTypeName: Boolean = false - def toTermName: TermName = this - def toTypeName: TypeName = { - val h = hashValue(chrs, index, len) & HASH_MASK - var n = typeHashtable(h) - while ((n ne null) && n.start != index) - n = n.next; - if (n eq null) - n = new TypeName(index, len, h); - n - } - def append(suffix: String): TermName = newTermName(this + suffix) - def append(suffix: Name): TermName = append(suffix.toString) - def companionName: TypeName = toTypeName - def subName(from: Int, to: Int): TermName = - newTermName(chrs, start + from, to - from) - } - - final class TypeName(_index: Int, _len: Int, hash: Int) extends Name(_index, _len) { - var next: TypeName = typeHashtable(hash) - typeHashtable(hash) = this - def isTermName: Boolean = false - def isTypeName: Boolean = true - def toTermName: TermName = { - val h = hashValue(chrs, index, len) & HASH_MASK - var n = termHashtable(h) - while ((n ne null) && n.start != index) - n = n.next; - if (n eq null) - n = new TermName(index, len, h); - n - } - def toTypeName: TypeName = this - - def append(suffix: String): TypeName = newTypeName(this + suffix) - def append(suffix: Name): TypeName = append(suffix.toString) - def companionName: TermName = toTermName - def subName(from: Int, to: Int): TypeName = - newTypeName(chrs, start + from, to - from) - } -} diff --git a/src/compiler/scala/tools/nsc/symtab/Positions.scala b/src/compiler/scala/tools/nsc/symtab/Positions.scala index 2290705bbf..ff20e70541 100644 --- a/src/compiler/scala/tools/nsc/symtab/Positions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Positions.scala @@ -3,35 +3,19 @@ package symtab import scala.tools.nsc.util.{ SourceFile, Position, OffsetPosition, NoPosition } -trait Positions { +trait Positions extends scala.reflect.common.Positions { self: scala.tools.nsc.symtab.SymbolTable => def rangePos(source: SourceFile, start: Int, point: Int, end: Int) = new OffsetPosition(source, point) - /** A position that wraps a set of trees. - * The point of the wrapping position is the point of the default position. - * If some of the trees are ranges, returns a range position enclosing all ranges - * Otherwise returns default position. - */ - def wrappingPos(default: Position, trees: List[Tree]): Position = default - - /** A position that wraps the non-empty set of trees. - * The point of the wrapping position is the point of the first trees' position. - * If all some the trees are non-synthetic, returns a range position enclosing the non-synthetic trees - * Otherwise returns a synthetic offset position to point. - */ - def wrappingPos(trees: List[Tree]): Position = trees.head.pos - - /** Ensure that given tree has no positions that overlap with - * any of the positions of `others`. This is done by - * shortening the range or assigning TransparentPositions - * to some of the nodes in `tree`. - */ - def ensureNonOverlapping(tree: Tree, others: List[Tree]) {} - def validatePositions(tree: Tree) {} type Position = scala.tools.nsc.util.Position val NoPosition = scala.tools.nsc.util.NoPosition + + def focusPos(pos: Position): Position = pos.focus + def isRangePos(pos: Position): Boolean = pos.isRange + def showPos(pos: Position): String = pos.show + } diff --git a/src/compiler/scala/tools/nsc/symtab/Scopes.scala b/src/compiler/scala/tools/nsc/symtab/Scopes.scala index dd79605cbe..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/Scopes.scala +++ b/src/compiler/scala/tools/nsc/symtab/Scopes.scala @@ -1,336 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package symtab - -// Martin: I am about 1/4 way on a cleanup of scopes. -// The most important change is that scopes are now Iterables. -// This removed the need for the various iterators on ScopeEntries. -// ScopeEntries are conceptually an internal representation detail, -// so it's better not to return them in public iterators. -// It's true that other code also references ScopeEntries but that's -// done for performance (and could be reviewed). -// Another addition is a lookupAll method that returns all symbols with -// a name in a scopein an iterator. -trait Scopes { - self: SymbolTable => - - class ScopeEntry(val sym: Symbol, val owner: Scope) { - /** the next entry in the hash bucket - */ - var tail: ScopeEntry = null - - /** the next entry in this scope - */ - var next: ScopeEntry = null - - override def hashCode(): Int = sym.name.start - override def toString(): String = sym.toString() - } - - /** - * @param sym ... - * @param owner ... - * @return ... - */ - private def newScopeEntry(sym: Symbol, owner: Scope): ScopeEntry = { - val e = new ScopeEntry(sym, owner) - e.next = owner.elems - owner.elems = e - e - } - - class Scope(initElems: ScopeEntry) extends AbsScope { - - var elems: ScopeEntry = initElems - - /** The number of times this scope is nested in another - */ - private var nestinglevel = 0 - - /** the hash table - */ - private var hashtable: Array[ScopeEntry] = null - - /** a cache for all elements, to be used by symbol iterator. - */ - private var elemsCache: List[Symbol] = null - - /** size and mask of hash tables - * todo: make hashtables grow? - */ - private val HASHSIZE = 0x80 - private val HASHMASK = 0x7f - - /** the threshold number of entries from which a hashtable is constructed. - */ - private val MIN_HASH = 8 - - if (size >= MIN_HASH) createHash() - - def this() = this(null: ScopeEntry) - - def this(base: Scope) = { - this(base.elems) - nestinglevel = base.nestinglevel + 1 - } - - def this(decls: List[Symbol]) = { - this() - decls foreach enter - } - - /** Returns a new scope with the same content as this one. */ - def cloneScope: Scope = { - val clone = new Scope() - this.toList foreach (clone enter _) - clone - } - - /** is the scope empty? */ - override def isEmpty: Boolean = elems eq null - - /** the number of entries in this scope */ - override def size: Int = { - var s = 0 - var e = elems - while (e ne null) { - s += 1 - e = e.next - } - s - } - - /** enter a scope entry - * - * @param e ... - */ - def enter(e: ScopeEntry) { - elemsCache = null - if (hashtable ne null) { - val i = e.sym.name.start & HASHMASK - elems.tail = hashtable(i) - hashtable(i) = elems - } else if (size >= MIN_HASH) { - createHash() - } - } - - /** enter a symbol - * - * @param sym ... - */ - def enter(sym: Symbol): Symbol = { enter(newScopeEntry(sym, this)); sym } - - /** enter a symbol, asserting that no symbol with same name exists in scope - * - * @param sym ... - */ - def enterUnique(sym: Symbol) { - assert(lookup(sym.name) == NoSymbol) - enter(sym) - } - - private def createHash() { - hashtable = new Array[ScopeEntry](HASHSIZE) - enterInHash(elems) - } - - private def enterInHash(e: ScopeEntry) { - if (e ne null) { - enterInHash(e.next) - val i = e.sym.name.start & HASHMASK - e.tail = hashtable(i) - hashtable(i) = e - } - } - - def rehash(sym: Symbol, newname: Name) { - if (hashtable ne null) { - val index = sym.name.start & HASHMASK - var e1 = hashtable(index) - var e: ScopeEntry = null - if (e1 != null) { - if (e1.sym == sym) { - hashtable(index) = e1.tail - e = e1 - } else { - while (e1.tail != null && e1.tail.sym != sym) e1 = e1.tail - if (e1.tail != null) { - e = e1.tail - e1.tail = e.tail - } - } - } - if (e != null) { - val newindex = newname.start & HASHMASK - e.tail = hashtable(newindex) - hashtable(newindex) = e - } - } - } - - /** remove entry - * - * @param e ... - */ - def unlink(e: ScopeEntry) { - if (elems == e) { - elems = e.next - } else { - var e1 = elems - while (e1.next != e) e1 = e1.next - e1.next = e.next - } - if (hashtable ne null) { - val index = e.sym.name.start & HASHMASK - var e1 = hashtable(index) - if (e1 == e) { - hashtable(index) = e.tail - } else { - while (e1.tail != e) e1 = e1.tail; - e1.tail = e.tail - } - } - elemsCache = null - } - - /** remove symbol */ - def unlink(sym: Symbol) { - var e = lookupEntry(sym.name) - while (e ne null) { - if (e.sym == sym) unlink(e); - e = lookupNextEntry(e) - } - } - - /** lookup a symbol - * - * @param name ... - * @return ... - */ - def lookup(name: Name): Symbol = { - val e = lookupEntry(name) - if (e eq null) NoSymbol else e.sym - } - - /** Returns an iterator yielding every symbol with given name in this scope. - */ - def lookupAll(name: Name): Iterator[Symbol] = new Iterator[Symbol] { - var e = lookupEntry(name) - def hasNext: Boolean = e ne null - def next: Symbol = { val r = e.sym; e = lookupNextEntry(e); r } - } - - /** lookup a symbol entry matching given name. - * @note from Martin: I believe this is a hotspot or will be one - * in future versions of the type system. I have reverted the previous - * change to use iterators as too costly. - */ - def lookupEntry(name: Name): ScopeEntry = { - var e: ScopeEntry = null - if (hashtable ne null) { - e = hashtable(name.start & HASHMASK) - while ((e ne null) && e.sym.name != name) { - e = e.tail - } - } else { - e = elems - while ((e ne null) && e.sym.name != name) { - e = e.next - } - } - e - } - - /** lookup next entry with same name as this one - * @note from Martin: I believe this is a hotspot or will be one - * in future versions of the type system. I have reverted the previous - * change to use iterators as too costly. - */ - def lookupNextEntry(entry: ScopeEntry): ScopeEntry = { - var e = entry - if (hashtable ne null) - do { e = e.tail } while ((e ne null) && e.sym.name != entry.sym.name) - else - do { e = e.next } while ((e ne null) && e.sym.name != entry.sym.name); - e - } - - /** Return all symbols as a list in the order they were entered in this scope. - */ - override def toList: List[Symbol] = { - if (elemsCache eq null) { - elemsCache = Nil - var e = elems - while ((e ne null) && e.owner == this) { - elemsCache = e.sym :: elemsCache - e = e.next - } - } - elemsCache - } - - /** Return the nesting level of this scope, i.e. the number of times this scope - * was nested in another */ - def nestingLevel = nestinglevel - - /** Return all symbols as an iterator in the order they were entered in this scope. - */ - def iterator: Iterator[Symbol] = toList.iterator - -/* - /** Does this scope contain an entry for `sym`? - */ - def contains(sym: Symbol): Boolean = lookupAll(sym.name) contains sym - - /** A scope that contains all symbols of this scope and that also contains `sym`. - */ - def +(sym: Symbol): Scope = - if (contains(sym)) this - else { - val result = cloneScope - result enter sym - result - } - - /** A scope that contains all symbols of this scope except `sym`. - */ - def -(sym: Symbol): Scope = - if (!contains(sym)) this - else { - val result = cloneScope - result unlink sym - result - } -*/ - override def foreach[U](p: Symbol => U): Unit = toList foreach p - - override def filter(p: Symbol => Boolean): Scope = - if (!(toList forall p)) new Scope(toList filter p) else this - - override def mkString(start: String, sep: String, end: String) = - toList.map(_.defString).mkString(start, sep, end) - - override def toString(): String = mkString("Scope{\n ", ";\n ", "\n}") - - } - - def newScope: Scope = new Scope - - /** The empty scope (immutable). - */ - object EmptyScope extends Scope { - override def enter(e: ScopeEntry) { - abort("EmptyScope.enter") - } - } - - /** The error scope. - */ - class ErrorScope(owner: Symbol) extends Scope(null: ScopeEntry) -} - diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 4a7f52f2b5..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -1,589 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package symtab - -import scala.collection.immutable - -trait StdNames extends reflect.generic.StdNames with NameManglers { - self: SymbolTable => - - /** This should be the first trait in the linearization. */ - trait CompilerKeywords { - private var kws: Set[TermName] = Set() - private def kw(s: String): TermName = { - val result = newTermName(s) - kws = kws + result - result - } - - final val ABSTRACTkw: TermName = kw("abstract") - final val CASEkw: TermName = kw("case") - final val CLASSkw: TermName = kw("class") - final val CATCHkw: TermName = kw("catch") - final val DEFkw: TermName = kw("def") - final val DOkw: TermName = kw("do") - final val ELSEkw: TermName = kw("else") - final val EXTENDSkw: TermName = kw("extends") - final val FALSEkw: TermName = kw("false") - final val FINALkw: TermName = kw("final") - final val FINALLYkw: TermName = kw("finally") - final val FORkw: TermName = kw("for") - final val FORSOMEkw: TermName = kw("forSome") - final val IFkw: TermName = kw("if") - final val IMPLICITkw: TermName = kw("implicit") - final val IMPORTkw: TermName = kw("import") - final val LAZYkw: TermName = kw("lazy") - final val MATCHkw: TermName = kw("match") - final val NEWkw: TermName = kw("new") - final val NULLkw: TermName = kw("null") - final val OBJECTkw: TermName = kw("object") - final val OVERRIDEkw: TermName = kw("override") - final val PACKAGEkw: TermName = kw("package") - final val PRIVATEkw: TermName = kw("private") - final val PROTECTEDkw: TermName = kw("protected") - final val RETURNkw: TermName = kw("return") - final val SEALEDkw: TermName = kw("sealed") - final val SUPERkw: TermName = kw("super") - final val THISkw: TermName = kw("this") - final val THROWkw: TermName = kw("throw") - final val TRAITkw: TermName = kw("trait") - final val TRUEkw: TermName = kw("true") - final val TRYkw: TermName = kw("try") - final val TYPEkw: TermName = kw("type") - final val VALkw: TermName = kw("val") - final val VARkw: TermName = kw("var") - final val WITHkw: TermName = kw("with") - final val WHILEkw: TermName = kw("while") - final val YIELDkw: TermName = kw("yield") - final val DOTkw: TermName = kw(".") - final val USCOREkw: TermName = kw("_") - final val COLONkw: TermName = kw(":") - final val EQUALSkw: TermName = kw("=") - final val ARROWkw: TermName = kw("=>") - final val LARROWkw: TermName = kw("<-") - final val SUBTYPEkw: TermName = kw("<:") - final val VIEWBOUNDkw: TermName = kw("<%") - final val SUPERTYPEkw: TermName = kw(">:") - final val HASHkw: TermName = kw("#") - final val ATkw: TermName = kw("@") - - final val keywords = { - val result = kws.toSet - kws = null - result - } - - final val javaKeywords = new JavaKeywords() - } - - trait CompilerCommonNames extends LibraryCommonNames { - // value types are all used as terms as well - final val Boolean: NameType = "Boolean" - final val Byte: NameType = "Byte" - final val Char: NameType = "Char" - final val Double: NameType = "Double" - final val Float: NameType = "Float" - final val Int: NameType = "Int" - final val Long: NameType = "Long" - final val Short: NameType = "Short" - final val Unit: NameType = "Unit" - - final val ScalaValueNames: scala.List[NameType] = - scala.List(Byte, Char, Short, Int, Long, Float, Double, Boolean, Unit) - - // types whose companions we utilize - final val Array: NameType = "Array" - final val List: NameType = "List" - final val Seq: NameType = "Seq" - final val Symbol: NameType = "Symbol" - - // fictions we use as both types and terms - final val ERROR: NameType = "<error>" - final val NO_NAME: NameType = "<none>" // formerly NOSYMBOL - final val WILDCARD: NameType = "_" - } - - trait CompilerTypeNames extends CompilerCommonNames { - final val BYNAME_PARAM_CLASS_NAME: NameType = "<byname>" - final val EQUALS_PATTERN_NAME: NameType = "<equals>" - final val JAVA_REPEATED_PARAM_CLASS_NAME: NameType = "<repeated...>" - final val LOCAL_CHILD: NameType = "<local child>" - final val REPEATED_PARAM_CLASS_NAME: NameType = "<repeated>" - final val WILDCARD_STAR: NameType = "_*" - - final val Any: NameType = "Any" - final val AnyRef: NameType = "AnyRef" - final val AnyVal: NameType = "AnyVal" - final val Nothing: NameType = "Nothing" - final val Null: NameType = "Null" - final val Object: NameType = "Object" - final val PartialFunction: NameType = "PartialFunction" - final val Product: NameType = "Product" - final val ScalaObject: NameType = "ScalaObject" - final val Serializable: NameType = "Serializable" - final val Singleton: NameType = "Singleton" - final val String: NameType = "String" - final val Throwable: NameType = "Throwable" - - // Annotation types - final val AnnotationDefaultATTR: NameType = "AnnotationDefault" - final val BridgeATTR: NameType = "Bridge" - final val ClassfileAnnotationATTR: NameType = "RuntimeInvisibleAnnotations" // RetentionPolicy.CLASS. Currently not used (Apr 2009). - final val CodeATTR: NameType = "Code" - final val ConstantValueATTR: NameType = "ConstantValue" - final val DeprecatedATTR: NameType = "Deprecated" - final val ExceptionsATTR: NameType = "Exceptions" - final val InnerClassesATTR: NameType = "InnerClasses" - final val JacoMetaATTR: NameType = "JacoMeta" - final val LineNumberTableATTR: NameType = "LineNumberTable" - final val LocalVariableTableATTR: NameType = "LocalVariableTable" - final val RuntimeAnnotationATTR: NameType = "RuntimeVisibleAnnotations" // RetentionPolicy.RUNTIME - final val RuntimeParamAnnotationATTR: NameType = "RuntimeVisibleParameterAnnotations" // RetentionPolicy.RUNTIME (annotations on parameters) - final val ScalaATTR: NameType = "Scala" - final val ScalaSignatureATTR: NameType = "ScalaSig" - final val SignatureATTR: NameType = "Signature" - final val SourceFileATTR: NameType = "SourceFile" - final val SyntheticATTR: NameType = "Synthetic" - } - - - trait CompilerTermNames extends CompilerKeywords with CompilerCommonNames { - // Compiler internal names - val ANYNAME: NameType = "<anyname>" - val CONSTRUCTOR: NameType = "<init>" - val FAKE_LOCAL_THIS: NameType = "this$" - val INITIALIZER: NameType = CONSTRUCTOR // Is this buying us something? - val MIXIN_CONSTRUCTOR: NameType = "$init$" - val MODULE_INSTANCE_FIELD: NameType = "MODULE$" - val OUTER: NameType = "$outer" - val OUTER_LOCAL: NameType = "$outer " // note the space - val SELF: NameType = "$this" - val SPECIALIZED_INSTANCE: NameType = "specInstance$" - val STAR: NameType = "*" - val THIS: NameType = "_$this" - - final val Nil: NameType = "Nil" - final val Predef: NameType = "Predef" - final val ScalaRunTime: NameType = "ScalaRunTime" - final val Some: NameType = "Some" - - // Compiler utilized names - // val productElementName: NameType = "productElementName" - val TYPE_ : NameType = "TYPE" - val add_ : NameType = "add" - val apply: NameType = "apply" - val arrayValue: NameType = "arrayValue" - val arraycopy: NameType = "arraycopy" - val asInstanceOf_ : NameType = "asInstanceOf" - val assert_ : NameType = "assert" - val assume_ : NameType = "assume" - val box: NameType = "box" - val bytes: NameType = "bytes" - val canEqual_ : NameType = "canEqual" - val checkInitialized: NameType = "checkInitialized" - val classOf: NameType = "classOf" - val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure - val conforms: NameType = "conforms" - val copy: NameType = "copy" - val delayedInit: NameType = "delayedInit" - val delayedInitArg: NameType = "delayedInit$body" - val drop: NameType = "drop" - val elem: NameType = "elem" - val eq: NameType = "eq" - val equals_ : NameType = if (forMSIL) "Equals" else "equals" - val error: NameType = "error" - val ex: NameType = "ex" - val false_ : NameType = "false" - val filter: NameType = "filter" - val finalize_ : NameType = if (forMSIL) "Finalize" else "finalize" - val find_ : NameType = "find" - val flatMap: NameType = "flatMap" - val foreach: NameType = "foreach" - val genericArrayOps: NameType = "genericArrayOps" - val get: NameType = "get" - val hasNext: NameType = "hasNext" - val hashCode_ : NameType = if (forMSIL) "GetHashCode" else "hashCode" - val hash_ : NameType = "hash" - val head: NameType = "head" - val identity: NameType = "identity" - val inlinedEquals: NameType = "inlinedEquals" - val applyDynamic: NameType = "applyDynamic" - val isArray: NameType = "isArray" - val isDefinedAt: NameType = "isDefinedAt" - val isEmpty: NameType = "isEmpty" - val isInstanceOf_ : NameType = "isInstanceOf" - val java: NameType = "java" - val lang: NameType = "lang" - val length: NameType = "length" - val lengthCompare: NameType = "lengthCompare" - val lift_ : NameType = "lift" - val main: NameType = "main" - val map: NameType = "map" - val ne: NameType = "ne" - val newArray: NameType = "newArray" - val next: NameType = "next" - val notifyAll_ : NameType = "notifyAll" - val notify_ : NameType = "notify" - val null_ : NameType = "null" - val ofDim: NameType = "ofDim" - val productArity: NameType = "productArity" - val productElement: NameType = "productElement" - val productPrefix: NameType = "productPrefix" - val readResolve: NameType = "readResolve" - val sameElements: NameType = "sameElements" - val scala_ : NameType = "scala" - val self: NameType = "self" - val setAccessible: NameType = "setAccessible" - val synchronized_ : NameType = "synchronized" - val tail: NameType = "tail" - val this_ : NameType = "this" - val throw_ : NameType = "throw" - val toArray: NameType = "toArray" - val toList: NameType = "toList" - val toSeq: NameType = "toSeq" - val toString_ : NameType = if (forMSIL) "ToString" else "toString" - val true_ : NameType = "true" - val unapply: NameType = "unapply" - val unapplySeq: NameType = "unapplySeq" - val unbox: NameType = "unbox" - val update: NameType = "update" - val value: NameType = "value" - val view_ : NameType = "view" - val wait_ : NameType = "wait" - val withFilter: NameType = "withFilter" - val wrapRefArray: NameType = "wrapRefArray" - val zip: NameType = "zip" - - // unencoded operators - object raw { - final val AMP : NameType = "&" - final val BANG : NameType = "!" - final val BAR : NameType = "|" - final val DOLLAR: NameType = "$" - final val GE: NameType = ">=" - final val LE: NameType = "<=" - final val MINUS: NameType = "-" - final val NE: NameType = "!=" - final val PLUS : NameType = "+" - final val SLASH: NameType = "/" - final val STAR : NameType = "*" - final val TILDE: NameType = "~" - - final val isUnary: Set[Name] = Set(MINUS, PLUS, TILDE, BANG) - } - - // value-conversion methods - val toByte: NameType = "toByte" - val toShort: NameType = "toShort" - val toChar: NameType = "toChar" - val toInt: NameType = "toInt" - val toLong: NameType = "toLong" - val toFloat: NameType = "toFloat" - val toDouble: NameType = "toDouble" - } - - object tpnme extends CompilerTypeNames with LibraryTypeNames with TypeNameMangling { - type NameType = TypeName - implicit def createNameType(name: String): TypeName = newTypeName(name) - } - - val javanme = nme.javaKeywords - - object nme extends CompilerTermNames with LibraryTermNames with TermNameMangling { - type NameType = TermName - implicit def createNameType(name: String): TermName = newTermName(name) - - /** Translate a String into a list of simple TypeNames and TermNames. - * In all segments before the last, type/term is determined by whether - * the following separator char is '.' or '#'. In the last segment, - * the argument "assumeTerm" determines it. Examples: - * - * package foo { - * object Lorax { object Wog ; class Wog } - * class Lorax { object Zax ; class Zax } - * } - * - * f("foo.Lorax", true) == List("foo": Term, "Lorax": Term) // object Lorax - * f("foo.Lorax", false) == List("foo": Term, "Lorax": Type) // class Lorax - * f("Lorax.Wog", true) == List("Lorax": Term, "Wog": Term) // object Wog - * f("Lorax.Wog", false) == List("Lorax": Term, "Wog": Type) // class Wog - * f("Lorax#Zax", true) == List("Lorax": Type, "Zax": Term) // object Zax - * f("Lorax#Zax", false) == List("Lorax": Type, "Zax": Type) // class Zax - * - * Note that in actual scala syntax you cannot refer to object Zax without an - * instance of Lorax, so Lorax#Zax could only mean the type. One might think - * that Lorax#Zax.type would work, but this is not accepted by the parser. - * For the purposes of referencing that object, the syntax is allowed. - */ - def segments(name: String, assumeTerm: Boolean): List[Name] = { - def mkName(str: String, term: Boolean): Name = - if (term) newTermName(str) else newTypeName(str) - - name.indexWhere(ch => ch == '.' || ch == '#') match { - // it's the last segment: the parameter tells us whether type or term - case -1 => if (name == "") scala.Nil else scala.List(mkName(name, assumeTerm)) - // otherwise, we can tell based on whether '#' or '.' is the following char. - case idx => - val (simple, div, rest) = (name take idx, name charAt idx, name drop (idx + 1)) - mkName(simple, div == '.') :: segments(rest, assumeTerm) - } - } - private def bitmapName(n: Int, suffix: String): TermName = - newTermName(BITMAP_PREFIX + suffix + n) - - /** The name of bitmaps for initialized (public or protected) lazy vals. */ - def bitmapName(n: Int): TermName = bitmapName(n, "") - - /** The name of bitmaps for initialized transient lazy vals. */ - def bitmapNameForTransient(n: Int): TermName = bitmapName(n, "trans$") - - /** The name of bitmaps for initialized private lazy vals. */ - def bitmapNameForPrivate(n: Int): TermName = bitmapName(n, "priv$") - - /** The name of bitmaps for checkinit values */ - def bitmapNameForCheckinit(n: Int): TermName = bitmapName(n, "init$") - - /** The name of bitmaps for checkinit values that have transient flag*/ - def bitmapNameForCheckinitTransient(n: Int): TermName = bitmapName(n, "inittrans$") - - /** Base strings from which synthetic names are derived. */ - val BITMAP_PREFIX = "bitmap$" - val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$" - val DEFAULT_GETTER_STRING = "$default$" - val DO_WHILE_PREFIX = "doWhile$" - val EQEQ_LOCAL_VAR = "eqEqTemp$" - val EVIDENCE_PARAM_PREFIX = "evidence$" - val EXCEPTION_RESULT_PREFIX = "exceptionResult" - val INTERPRETER_IMPORT_WRAPPER = "$iw" - val INTERPRETER_LINE_PREFIX = "line" - val INTERPRETER_SYNTHVAR_PREFIX = "synthvar$" - val INTERPRETER_VAR_PREFIX = "res" - val INTERPRETER_WRAPPER_SUFFIX = "$object" - val WHILE_PREFIX = "while$" - - def getCause = sn.GetCause - def getClass_ = sn.GetClass - def getMethod_ = sn.GetMethod - def invoke_ = sn.Invoke - - val ADD = encode("+") - val AND = encode("&") - val ASR = encode(">>") - val DIV = encode("/") - val EQ = encode("==") - val EQL = encode("=") - val GE = encode(">=") - val GT = encode(">") - val HASHHASH = encode("##") - val LE = encode("<=") - val LSL = encode("<<") - val LSR = encode(">>>") - val LT = encode("<") - val MINUS = encode("-") - val MOD = encode("%") - val MUL = encode("*") - val NE = encode("!=") - val OR = encode("|") - val PLUS = encode("+") - val SUB = encode("-") - val XOR = encode("^") - val ZAND = encode("&&") - val ZOR = encode("||") - - // unary operators - val UNARY_~ = encode("unary_~") - val UNARY_+ = encode("unary_+") - val UNARY_- = encode("unary_-") - val UNARY_! = encode("unary_!") - } - - abstract class SymbolNames { - protected implicit def stringToTypeName(s: String): TypeName = newTypeName(s) - - val BeanProperty : TypeName - val BooleanBeanProperty : TypeName - val BoxedBoolean : TypeName - val BoxedCharacter : TypeName - val BoxedNumber : TypeName - val Class : TypeName - val Code : TypeName - val Delegate : TypeName - val IOOBException : TypeName // IndexOutOfBoundsException - val InvTargetException : TypeName // InvocationTargetException - val JavaSerializable : TypeName - val MethodAsObject : TypeName - val NPException : TypeName // NullPointerException - val Object : TypeName - val String : TypeName - val Throwable : TypeName - val ValueType : TypeName - - val ForName : TermName - val GetCause : TermName - val GetClass : TermName - val GetMethod : TermName - val Invoke : TermName - val JavaLang : TermName - - val Boxed: immutable.Map[TypeName, TypeName] - } - - class JavaKeywords { - private var kws: Set[TermName] = Set() - private def kw(s: String): TermName = { - val result = newTermName(s) - kws = kws + result - result - } - - final val ABSTRACTkw: TermName = kw("abstract") - final val ASSERTkw: TermName = kw("assert") - final val BOOLEANkw: TermName = kw("boolean") - final val BREAKkw: TermName = kw("break") - final val BYTEkw: TermName = kw("byte") - final val CASEkw: TermName = kw("case") - final val CATCHkw: TermName = kw("catch") - final val CHARkw: TermName = kw("char") - final val CLASSkw: TermName = kw("class") - final val CONSTkw: TermName = kw("const") - final val CONTINUEkw: TermName = kw("continue") - final val DEFAULTkw: TermName = kw("default") - final val DOkw: TermName = kw("do") - final val DOUBLEkw: TermName = kw("double") - final val ELSEkw: TermName = kw("else") - final val ENUMkw: TermName = kw("enum") - final val EXTENDSkw: TermName = kw("extends") - final val FINALkw: TermName = kw("final") - final val FINALLYkw: TermName = kw("finally") - final val FLOATkw: TermName = kw("float") - final val FORkw: TermName = kw("for") - final val IFkw: TermName = kw("if") - final val GOTOkw: TermName = kw("goto") - final val IMPLEMENTSkw: TermName = kw("implements") - final val IMPORTkw: TermName = kw("import") - final val INSTANCEOFkw: TermName = kw("instanceof") - final val INTkw: TermName = kw("int") - final val INTERFACEkw: TermName = kw("interface") - final val LONGkw: TermName = kw("long") - final val NATIVEkw: TermName = kw("native") - final val NEWkw: TermName = kw("new") - final val PACKAGEkw: TermName = kw("package") - final val PRIVATEkw: TermName = kw("private") - final val PROTECTEDkw: TermName = kw("protected") - final val PUBLICkw: TermName = kw("public") - final val RETURNkw: TermName = kw("return") - final val SHORTkw: TermName = kw("short") - final val STATICkw: TermName = kw("static") - final val STRICTFPkw: TermName = kw("strictfp") - final val SUPERkw: TermName = kw("super") - final val SWITCHkw: TermName = kw("switch") - final val SYNCHRONIZEDkw: TermName = kw("synchronized") - final val THISkw: TermName = kw("this") - final val THROWkw: TermName = kw("throw") - final val THROWSkw: TermName = kw("throws") - final val TRANSIENTkw: TermName = kw("transient") - final val TRYkw: TermName = kw("try") - final val VOIDkw: TermName = kw("void") - final val VOLATILEkw: TermName = kw("volatile") - final val WHILEkw: TermName = kw("while") - - final val keywords = { - val result = kws.toSet - kws = null - result - } - } - - private abstract class JavaNames extends SymbolNames { - final val BoxedBoolean: TypeName = "java.lang.Boolean" - final val BoxedByte: TypeName = "java.lang.Byte" - final val BoxedCharacter: TypeName = "java.lang.Character" - final val BoxedDouble: TypeName = "java.lang.Double" - final val BoxedFloat: TypeName = "java.lang.Float" - final val BoxedInteger: TypeName = "java.lang.Integer" - final val BoxedLong: TypeName = "java.lang.Long" - final val BoxedNumber: TypeName = "java.lang.Number" - final val BoxedShort: TypeName = "java.lang.Short" - final val Class: TypeName = "java.lang.Class" - final val Delegate: TypeName = tpnme.NO_NAME - final val IOOBException: TypeName = "java.lang.IndexOutOfBoundsException" - final val InvTargetException: TypeName = "java.lang.reflect.InvocationTargetException" - final val MethodAsObject: TypeName = "java.lang.reflect.Method" - final val NPException: TypeName = "java.lang.NullPointerException" - final val Object: TypeName = "java.lang.Object" - final val String: TypeName = "java.lang.String" - final val Throwable: TypeName = "java.lang.Throwable" - final val ValueType: TypeName = tpnme.NO_NAME - - final val ForName: TermName = "forName" - final val GetCause: TermName = "getCause" - final val GetClass: TermName = "getClass" - final val GetMethod: TermName = "getMethod" - final val Invoke: TermName = "invoke" - final val JavaLang: TermName = "java.lang" - - val Boxed = immutable.Map[TypeName, TypeName]( - tpnme.Boolean -> BoxedBoolean, - tpnme.Byte -> BoxedByte, - tpnme.Char -> BoxedCharacter, - tpnme.Short -> BoxedShort, - tpnme.Int -> BoxedInteger, - tpnme.Long -> BoxedLong, - tpnme.Float -> BoxedFloat, - tpnme.Double -> BoxedDouble - ) - } - - private class MSILNames extends SymbolNames { - final val BeanProperty: TypeName = tpnme.NO_NAME - final val BooleanBeanProperty: TypeName = tpnme.NO_NAME - final val BoxedBoolean: TypeName = "System.IConvertible" - final val BoxedCharacter: TypeName = "System.IConvertible" - final val BoxedNumber: TypeName = "System.IConvertible" - final val Class: TypeName = "System.Type" - final val Code: TypeName = tpnme.NO_NAME - final val Delegate: TypeName = "System.MulticastDelegate" - final val IOOBException: TypeName = "System.IndexOutOfRangeException" - final val InvTargetException: TypeName = "System.Reflection.TargetInvocationException" - final val JavaSerializable: TypeName = tpnme.NO_NAME - final val MethodAsObject: TypeName = "System.Reflection.MethodInfo" - final val NPException: TypeName = "System.NullReferenceException" - final val Object: TypeName = "System.Object" - final val String: TypeName = "System.String" - final val Throwable: TypeName = "System.Exception" - final val ValueType: TypeName = "System.ValueType" - - final val ForName: TermName = "GetType" - final val GetCause: TermName = "InnerException" /* System.Reflection.TargetInvocationException.InnerException */ - final val GetClass: TermName = "GetType" - final val GetMethod: TermName = "GetMethod" - final val Invoke: TermName = "Invoke" - final val JavaLang: TermName = "System" - - val Boxed = immutable.Map[TypeName, TypeName]( - tpnme.Boolean -> "System.Boolean", - tpnme.Byte -> "System.SByte", // a scala.Byte is signed and a System.SByte too (unlike a System.Byte) - tpnme.Char -> "System.Char", - tpnme.Short -> "System.Int16", - tpnme.Int -> "System.Int32", - tpnme.Long -> "System.Int64", - tpnme.Float -> "System.Single", - tpnme.Double -> "System.Double" - ) - } - - private class J2SENames extends JavaNames { - final val BeanProperty: TypeName = "scala.reflect.BeanProperty" - final val BooleanBeanProperty: TypeName = "scala.reflect.BooleanBeanProperty" - final val Code: TypeName = "scala.reflect.Code" - final val JavaSerializable: TypeName = "java.io.Serializable" - } - - lazy val sn: SymbolNames = - if (forMSIL) new MSILNames - else new J2SENames -} diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 3536e79a76..9f91d89158 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -10,10 +10,9 @@ import java.io.IOException import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Attribute => MSILAttribute } import scala.compat.Platform.currentTime -import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.util.{ ClassPath } import classfile.ClassfileParser -import Flags._ +import reflect.common.Flags._ import util.Statistics._ /** This class ... @@ -285,7 +284,7 @@ abstract class SymbolLoaders { classfileParser.parse(classfile, root) stopTimer(classReadNanos, start) } - override def sourcefile = classfileParser.srcfile + override def sourcefile: Option[AbstractFile] = classfileParser.srcfile } class MSILTypeLoader(typ: MSILType) extends SymbolLoader { diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala index d3decb0abc..d27374cc29 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala @@ -10,107 +10,4 @@ import ast.{Trees, TreePrinters, DocComments} import util._ -abstract class SymbolTable extends reflect.generic.Universe - with Names - with Symbols - with Types - with Scopes - with Caches - with Definitions - with reflect.generic.Constants - with BaseTypeSeqs - with InfoTransformers - with StdNames - with AnnotationInfos - with AnnotationCheckers - with Trees - with TreePrinters - with Positions - with DocComments - with TypeDebugging -{ - def settings: Settings - def rootLoader: LazyType - def log(msg: => AnyRef) - def abort(msg: String) = throw new Error(msg) - def abort() = throw new Error() - - /** Are we compiling for Java SE ? */ - def forJVM: Boolean - - /** Are we compiling for .NET ? */ - def forMSIL: Boolean - - /** A period is an ordinal number for a phase in a run. - * Phases in later runs have higher periods than phases in earlier runs. - * Later phases have higher periods than earlier phases in the same run. - */ - type Period = Int - final val NoPeriod = 0 - - /** An ordinal number for compiler runs. First run has number 1. */ - type RunId = Int - final val NoRunId = 0 - - private var ph: Phase = NoPhase - private var per = NoPeriod - - final def phase: Phase = ph - - final def phase_=(p: Phase) { - //System.out.println("setting phase to " + p) - assert((p ne null) && p != NoPhase) - ph = p - per = (currentRunId << 8) + p.id - } - - /** The current compiler run identifier. */ - def currentRunId: RunId - - /** The run identifier of the given period */ - final def runId(period: Period): RunId = period >> 8 - - /** The phase identifier of the given period */ - final def phaseId(period: Period): Phase#Id = period & 0xFF - - /** The period at the start of run that includes `period' */ - final def startRun(period: Period): Period = period & 0xFFFFFF00 - - /** The current period */ - final def currentPeriod: Period = { - //assert(per == (currentRunId << 8) + phase.id) - per - } - - /** The phase associated with given period */ - final def phaseOf(period: Period): Phase = phaseWithId(phaseId(period)) - - final def period(rid: RunId, pid: Phase#Id): Period = - (currentRunId << 8) + pid - - /** Perform given operation at given phase */ - final def atPhase[T](ph: Phase)(op: => T): T = { - // Eugene: insert same thread assertion here - val current = phase - phase = ph - try op - finally phase = current - } - final def afterPhase[T](ph: Phase)(op: => T): T = - atPhase(ph.next)(op) - - /** Break into repl debugger if assertion is true */ - // def breakIf(assertion: => Boolean, args: Any*): Unit = - // if (assertion) - // ILoop.break(args.toList) - - /** The set of all installed infotransformers */ - var infoTransformers = new InfoTransformer { - val pid = NoPhase.id - val changesBaseClasses = true - def transform(sym: Symbol, tpe: Type): Type = tpe - } - - /** The phase which has given index as identifier */ - val phaseWithId: Array[Phase] -} +abstract class SymbolTable extends reflect.common.SymbolTable diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index d1f5cbf4d2..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -1,2181 +0,0 @@ -/* 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.collection.mutable.ListBuffer -import io.AbstractFile -import util.{ Position, NoPosition, BatchSourceFile } -import util.Statistics._ -import Flags._ - -trait Symbols extends reflect.generic.Symbols { self: SymbolTable => - import definitions._ - - private var ids = 0 - def symbolCount = ids // statistics - - val emptySymbolArray = new Array[Symbol](0) - - /** Used for deciding in the IDE whether we can interrupt the compiler */ - //protected var activeLocks = 0 - - /** Used for debugging only */ - //protected var lockedSyms = collection.immutable.Set[Symbol]() - - /** Used to keep track of the recursion depth on locked symbols */ - private var recursionTable = immutable.Map.empty[Symbol, Int] - - private var nextexid = 0 - private def freshExistentialName(suffix: String) = { - nextexid += 1 - newTypeName("_" + nextexid + suffix) - } - - /** The original owner of a class. Used by the backend to generate - * EnclosingMethod attributes. - */ - val originalOwner = mutable.HashMap[Symbol, Symbol]() - - /** The class for all symbols */ - abstract class Symbol(initOwner: Symbol, initPos: Position, initName: Name) extends AbsSymbol { - var rawowner = initOwner - var rawname = initName - var rawflags = 0L - - private var rawpos = initPos - val id = { ids += 1; ids } // identity displayed when -uniqid - - var validTo: Period = NoPeriod - - def pos = rawpos - def setPos(pos: Position): this.type = { this.rawpos = pos; this } - -// annotations - - private var rawannots: List[AnnotationInfoBase] = Nil - def rawAnnotations = rawannots - - /* Used in namer to check whether annotations were already assigned or not */ - def hasAssignedAnnotations = rawannots.nonEmpty - - /** After the typer phase (before, look at the definition's Modifiers), contains - * the annotations attached to member a definition (class, method, type, field). - */ - def annotations: List[AnnotationInfo] = { - // .initialize: the type completer of the symbol parses the annotations, - // see "def typeSig" in Namers - val annots1 = initialize.rawannots map { - case x: LazyAnnotationInfo => x.annot() - case x: AnnotationInfo => x - } filterNot (_.atp.isError) - rawannots = annots1 - annots1 - } - - def setAnnotations(annots: List[AnnotationInfoBase]): this.type = { - this.rawannots = annots - this - } - - override def addAnnotation(annot: AnnotationInfo) { - setAnnotations(annot :: this.rawannots) - } - - /** Does this symbol have an annotation of the given class? */ - def hasAnnotation(cls: Symbol) = - getAnnotation(cls).isDefined - - def getAnnotation(cls: Symbol): Option[AnnotationInfo] = - annotations find (_.atp.typeSymbol == cls) - - /** Remove all annotations matching the given class. */ - def removeAnnotation(cls: Symbol): Unit = - setAnnotations(annotations filterNot (_.atp.typeSymbol == cls)) - - /** See comment in HasFlags for how privateWithin combines with flags. - */ - private[this] var _privateWithin: Symbol = _ - def privateWithin = _privateWithin - override def privateWithin_=(sym: Symbol) { _privateWithin = sym } - -// Creators ------------------------------------------------------------------- - - final def newValue(pos: Position, name: TermName) = - new TermSymbol(this, pos, name) - final def newValue(name: TermName, pos: Position = NoPosition) = - new TermSymbol(this, pos, name) - final def newVariable(pos: Position, name: TermName) = - newValue(pos, name).setFlag(MUTABLE) - final def newValueParameter(pos: Position, name: TermName) = - newValue(pos, name).setFlag(PARAM) - /** Create local dummy for template (owner of local blocks) */ - final def newLocalDummy(pos: Position) = - newValue(pos, nme.localDummyName(this)).setInfo(NoType) - final def newMethod(pos: Position, name: TermName) = - new MethodSymbol(this, pos, name).setFlag(METHOD) - final def newMethod(name: TermName, pos: Position = NoPosition) = - new MethodSymbol(this, pos, name).setFlag(METHOD) - final def newLabel(pos: Position, name: TermName) = - newMethod(pos, name).setFlag(LABEL) - final def newConstructor(pos: Position) = - newMethod(pos, nme.CONSTRUCTOR) - final def newModule(pos: Position, name: TermName, clazz: ClassSymbol) = - new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) - .setModuleClass(clazz) - final def newModule(name: TermName, clazz: Symbol, pos: Position = NoPosition) = - new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) - .setModuleClass(clazz.asInstanceOf[ClassSymbol]) - final def newModule(pos: Position, name: TermName) = { - val m = new ModuleSymbol(this, pos, name).setFlag(MODULE | FINAL) - m.setModuleClass(new ModuleClassSymbol(m)) - } - final def newPackage(pos: Position, name: TermName) = { - assert(name == nme.ROOT || isPackageClass) - val m = newModule(pos, name).setFlag(JAVA | PACKAGE) - m.moduleClass.setFlag(JAVA | PACKAGE) - m - } - final def newThisSym(pos: Position) = - newValue(pos, nme.this_).setFlag(SYNTHETIC) - final def newImport(pos: Position) = - newValue(pos, nme.IMPORT) - - /** @param pre type relative to which alternatives are seen. - * for instance: - * class C[T] { - * def m(x: T): T - * def m'(): T - * } - * val v: C[Int] - * - * Then v.m has symbol TermSymbol(flags = {OVERLOADED}, - * tpe = OverloadedType(C[Int], List(m, m'))) - * You recover the type of m doing a - * - * m.tpe.asSeenFrom(pre, C) (generally, owner of m, which is C here). - * - * or: - * - * pre.memberType(m) - */ - final def newOverloaded(pre: Type, alternatives: List[Symbol]): Symbol = - newValue(alternatives.head.pos, alternatives.head.name.toTermName) - .setFlag(OVERLOADED) - .setInfo(OverloadedType(pre, alternatives)) - - /** for explicit outer phase */ - final def newOuterAccessor(pos: Position) = { - val sym = newMethod(pos, nme.OUTER) - sym setFlag (STABLE | SYNTHETIC) - if (isTrait) sym setFlag DEFERRED - sym.expandName(this) - sym.referenced = this - sym - } - - final def newErrorValue(name: TermName) = - newValue(pos, name).setFlag(SYNTHETIC | IS_ERROR).setInfo(ErrorType) - - /** Symbol of a type definition type T = ... - */ - final def newAliasType(pos: Position, name: TypeName) = - new TypeSymbol(this, pos, name) - final def newAliasType(name: TypeName, pos: Position = NoPosition) = - new TypeSymbol(this, pos, name) - - /** Symbol of an abstract type type T >: ... <: ... - */ - final def newAbstractType(pos: Position, name: TypeName) = - new TypeSymbol(this, pos, name).setFlag(DEFERRED) - final def newAbstractType(name: TypeName, pos: Position = NoPosition) = - new TypeSymbol(this, pos, name).setFlag(DEFERRED) - - /** Symbol of a type parameter - */ - final def newTypeParameter(pos: Position, name: TypeName) = - newAbstractType(pos, name).setFlag(PARAM) - - /** Synthetic value parameters when parameter symbols are not available - */ - final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[Symbol]] = { - var cnt = 0 - def freshName() = { cnt += 1; newTermName("x$" + cnt) } - def param(tp: Type) = - newValueParameter(owner.pos.focus, freshName()).setFlag(SYNTHETIC).setInfo(tp) - argtypess map (_.map(param)) - } - - final def newExistential(pos: Position, name: TypeName): Symbol = - newAbstractType(pos, name).setFlag(EXISTENTIAL) - - final def freshExistential(suffix: String): Symbol = - newExistential(pos, freshExistentialName(suffix)) - - /** Synthetic value parameters when parameter symbols are not available. - * Calling this method multiple times will re-use the same parameter names. - */ - final def newSyntheticValueParams(argtypes: List[Type]): List[Symbol] = - newSyntheticValueParamss(List(argtypes)).head - - /** Synthetic value parameter when parameter symbol is not available. - * Calling this method multiple times will re-use the same parameter name. - */ - final def newSyntheticValueParam(argtype: Type): Symbol = - newSyntheticValueParams(List(argtype)).head - - /** Type skolems are type parameters ``seen from the inside'' - * Assuming a polymorphic method m[T], its type is a PolyType which has a TypeParameter - * with name `T' in its typeParams list. While type checking the parameters, result type and - * body of the method, there's a local copy of `T' which is a TypeSkolem. - */ - final def newTypeSkolem: Symbol = - new TypeSkolem(owner, pos, name.toTypeName, this) - .setFlag(flags) - - final def newClass(pos: Position, name: TypeName) = - new ClassSymbol(this, pos, name) - final def newClass(name: TypeName, pos: Position = NoPosition) = - new ClassSymbol(this, pos, name) - - final def newModuleClass(pos: Position, name: TypeName) = - new ModuleClassSymbol(this, pos, name) - final def newModuleClass(name: TypeName, pos: Position = NoPosition) = - new ModuleClassSymbol(this, pos, name) - - final def newAnonymousClass(pos: Position) = - newClass(pos, tpnme.ANON_CLASS_NAME) - final def newAnonymousFunctionClass(pos: Position) = - newClass(pos, tpnme.ANON_FUN_NAME) - - /** Refinement types P { val x: String; type T <: Number } - * also have symbols, they are refinementClasses - */ - final def newRefinementClass(pos: Position) = - newClass(pos, tpnme.REFINE_CLASS_NAME) - - /** Create a new getter for current symbol (which must be a field) - */ - final def newGetter: Symbol = { - val getter = owner.newMethod(pos.focus, nme.getterName(name)).setFlag(getterFlags(flags)) - getter.privateWithin = privateWithin - getter.setInfo(MethodType(List(), tpe)) - } - - final def newErrorClass(name: TypeName) = { - val clazz = newClass(pos, name).setFlag(SYNTHETIC | IS_ERROR) - clazz.setInfo(ClassInfoType(List(), new ErrorScope(this), clazz)) - clazz - } - - final def newErrorSymbol(name: Name): Symbol = name match { - case x: TypeName => newErrorClass(x) - case x: TermName => newErrorValue(x) - } - -// Locking and unlocking ------------------------------------------------------ - - // True if the symbol is unlocked. - // True if the symbol is locked but still below the allowed recursion depth. - // False otherwise - def lockOK: Boolean = { - ((rawflags & LOCKED) == 0L) || - ((settings.Yrecursion.value != 0) && - (recursionTable get this match { - case Some(n) => (n <= settings.Yrecursion.value) - case None => true })) - } - - // Lock a symbol, using the handler if the recursion depth becomes too great. - def lock(handler: => Unit) = { - if ((rawflags & LOCKED) != 0L) { - if (settings.Yrecursion.value != 0) { - recursionTable get this match { - case Some(n) => - if (n > settings.Yrecursion.value) { - handler - } else { - recursionTable += (this -> (n + 1)) - } - case None => - recursionTable += (this -> 1) - } - } else { handler } - } else { - rawflags |= LOCKED -// activeLocks += 1 -// lockedSyms += this - } - } - - // Unlock a symbol - def unlock() = { - if ((rawflags & LOCKED) != 0L) { -// activeLocks -= 1 -// lockedSyms -= this - rawflags = rawflags & ~LOCKED - if (settings.Yrecursion.value != 0) - recursionTable -= this - } - } - -// Tests ---------------------------------------------------------------------- - - /** Is this symbol a type but not a class? */ - def isNonClassType = false - - /** Term symbols with the exception of static parts of Java classes and packages. - */ - final def isValue = isTerm && !(isModule && hasFlag(PACKAGE | JAVA)) - - final def isVariable = isTerm && isMutable && !isMethod - - // interesting only for lambda lift. Captured variables are accessed from inner lambdas. - final def isCapturedVariable = isVariable && hasFlag(CAPTURED) - - final def isGetter = isTerm && hasAccessorFlag && !nme.isSetterName(name) - // todo: make independent of name, as this can be forged. - final def isSetter = isTerm && hasAccessorFlag && nme.isSetterName(name) - def isSetterParameter = isValueParameter && owner.isSetter - - final def hasGetter = isTerm && nme.isLocalName(name) - - final def isValueParameter = isTerm && hasFlag(PARAM) - final def isLocalDummy = isTerm && nme.isLocalDummyName(name) - final def isInitializedToDefault = !isType && hasAllFlags(DEFAULTINIT | ACCESSOR) - final def isClassConstructor = isTerm && (name == nme.CONSTRUCTOR) - final def isMixinConstructor = isTerm && (name == nme.MIXIN_CONSTRUCTOR) - final def isConstructor = isTerm && nme.isConstructorName(name) - final def isStaticModule = isModule && isStatic && !isMethod - final def isThisSym = isTerm && owner.thisSym == this - final def isError = hasFlag(IS_ERROR) - final def isErroneous = isError || isInitialized && tpe.isErroneous - override final def isTrait: Boolean = isClass && hasFlag(TRAIT | notDEFERRED) // A virtual class becomes a trait (part of DEVIRTUALIZE) - final def isTypeParameterOrSkolem = isType && hasFlag(PARAM) - final def isHigherOrderTypeParameter = owner.isTypeParameterOrSkolem - final def isTypeSkolem = isSkolem && hasFlag(PARAM) - // a type symbol bound by an existential type, for instance the T in - // List[T] forSome { type T } - final def isExistentialSkolem = isExistentiallyBound && isSkolem - final def isExistentialQuantified = isExistentiallyBound && !isSkolem - - // class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor - final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR) - - final def isAnonymousClass = isClass && (name containsName tpnme.ANON_CLASS_NAME) - final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME) - final def isAnonOrRefinementClass = isAnonymousClass || isRefinementClass - - final def isPackageObject = isModule && name == nme.PACKAGEkw && owner.isPackageClass - final def isPackageObjectClass = isModuleClass && name.toTermName == nme.PACKAGEkw && owner.isPackageClass - final def definedInPackage = owner.isPackageClass || owner.isPackageObjectClass - final def isJavaInterface = isJavaDefined && isTrait - final def needsFlatClasses: Boolean = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass - - // not printed as prefixes - final def isPredefModule = this == PredefModule - final def isScalaPackage = (this == ScalaPackage) || (isPackageObject && owner == ScalaPackageClass) - final def isScalaPackageClass = skipPackageObject == ScalaPackageClass - - /** If this is a package object or package object class, its owner: otherwise this. - */ - final def skipPackageObject: Symbol = if (isPackageObjectClass) owner else this - - /** If this is a constructor, its owner: otherwise this. - */ - final def skipConstructor: Symbol = if (isConstructor) owner else this - - /** Conditions where we omit the prefix when printing a symbol, to avoid - * unpleasantries like Predef.String, $iw.$iw.Foo and <empty>.Bippy. - */ - final def printWithoutPrefix = !settings.debug.value && ( - isScalaPackageClass || isPredefModule || isEffectiveRoot || isAnonOrRefinementClass || isInterpreterWrapper - ) - - /** Is symbol a monomorphic type? - * assumption: if a type starts out as monomorphic, it will not acquire - * type parameters in later phases. - */ - final def isMonomorphicType = - isType && { - var is = infos - (is eq null) || { - while (is.prev ne null) { is = is.prev } - is.info.isComplete && is.info.typeParams.isEmpty - } - } - - def isStrictFP = hasAnnotation(ScalaStrictFPAttr) || (enclClass hasAnnotation ScalaStrictFPAttr) - def isSerializable = info.baseClasses.exists(p => p == SerializableClass || p == JavaSerializableClass) || hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated - def isDeprecated = hasAnnotation(DeprecatedAttr) - def hasBridgeAnnotation = hasAnnotation(BridgeClass) - def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0) - def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1) - // !!! when annotation arguments are not literal strings, but any sort of - // assembly of strings, there is a fair chance they will turn up here not as - // Literal(const) but some arbitrary AST. However nothing in the compiler - // prevents someone from writing a @migration annotation with a calculated - // string. So this needs attention. For now the fact that migration is - // private[scala] ought to provide enough protection. - def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(2) } - def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) } - def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) } - - /** Does this symbol denote a wrapper created by the repl? */ - final def isInterpreterWrapper = (isModule || isModuleClass) && nme.isReplWrapperName(name) - - override def isEffectiveRoot = super.isEffectiveRoot || isInterpreterWrapper - - /** Is this symbol an accessor method for outer? */ - final def isOuterAccessor = { - hasFlag(STABLE | SYNTHETIC) && - originalName == nme.OUTER - } - - /** Is this symbol an accessor method for outer? */ - final def isOuterField = { - hasFlag(SYNTHETIC) && - originalName == nme.OUTER_LOCAL - } - - /** Does this symbol denote a stable value? */ - final def isStable = - isTerm && - !isMutable && - (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE)) && - !(tpe.isVolatile && !hasAnnotation(uncheckedStableClass)) - - def isVirtualClass = - hasFlag(DEFERRED) && isClass - - def isVirtualTrait = - hasFlag(DEFERRED) && isTrait - - def isLiftedMethod = isMethod && hasFlag(LIFTED) - def isCaseClass = isClass && isCase - - /** Does this symbol denote the primary constructor of its enclosing class? */ - final def isPrimaryConstructor = - isConstructor && owner.primaryConstructor == this - - /** Does this symbol denote an auxiliary constructor of its enclosing class? */ - final def isAuxiliaryConstructor = - isConstructor && !isPrimaryConstructor - - /** Is this symbol a synthetic apply or unapply method in a companion object of a case class? */ - final def isCaseApplyOrUnapply = - isMethod && isCase && isSynthetic - - /** Is this symbol a trait which needs an implementation class? */ - final def needsImplClass: Boolean = - isTrait && (!isInterface || hasFlag(lateINTERFACE)) && !isImplClass - - /** Is this a symbol which exists only in the implementation class, not in its trait? */ - final def isImplOnly: Boolean = - hasFlag(PRIVATE) || - (owner.isImplClass || owner.isTrait) && - ((hasFlag(notPRIVATE | LIFTED) && !hasFlag(ACCESSOR | SUPERACCESSOR | MODULE) || isConstructor) || - (hasFlag(LIFTED) && isModule && isMethod)) - - /** Is this symbol a module variable? - * This used to have to test for MUTABLE to distinguish the overloaded - * MODULEVAR/SYNTHETICMETH flag, but now SYNTHETICMETH is gone. - */ - final def isModuleVar = hasFlag(MODULEVAR) - - /** Is this symbol static (i.e. with no outer instance)? */ - final def isStatic: Boolean = - hasFlag(STATIC) || isRoot || owner.isStaticOwner - - /** Is this symbol a static constructor? */ - final def isStaticConstructor: Boolean = - isStaticMember && isClassConstructor - - /** Is this symbol a static member of its class? (i.e. needs to be implemented as a Java static?) */ - final def isStaticMember: Boolean = - hasFlag(STATIC) || owner.isImplClass - - /** Does this symbol denote a class that defines static symbols? */ - final def isStaticOwner: Boolean = - isPackageClass || isModuleClass && isStatic - - /** Is this symbol effectively final? I.e, it cannot be overridden */ - final def isEffectivelyFinal: Boolean = isFinal || isTerm && ( - hasFlag(PRIVATE) || isLocal || owner.isClass && owner.hasFlag(FINAL | MODULE)) - - /** Is this symbol locally defined? I.e. not accessed from outside `this' instance */ - final def isLocal: Boolean = owner.isTerm - - /** Is this symbol a constant? */ - final def isConstant: Boolean = - isStable && (tpe match { - case ConstantType(_) => true - case PolyType(_, ConstantType(_)) => true - case MethodType(_, ConstantType(_)) => true - case NullaryMethodType(ConstantType(_)) => true - case _ => false - }) - - /** Is this class nested in another class or module (not a package)? */ - final def isNestedClass: Boolean = - isClass && !isRoot && !owner.isPackageClass - - /** Is this class locally defined? - * A class is local, if - * - it is anonymous, or - * - its owner is a value - * - it is defined within a local class - */ - final def isLocalClass: Boolean = - isClass && (isAnonOrRefinementClass || isLocal || - !owner.isPackageClass && owner.isLocalClass) - -/* code for fixing nested objects - override final def isModuleClass: Boolean = - super.isModuleClass && !isExpandedModuleClass -*/ - /** Is this class or type defined as a structural refinement type? - */ - final def isStructuralRefinement: Boolean = - (isClass || isType || isModule) && info.normalize/*.underlying*/.isStructuralRefinement - - - /** Is this symbol a member of class `clazz' - */ - def isMemberOf(clazz: Symbol) = - clazz.info.member(name).alternatives contains this - - /** A a member of class `base' is incomplete if - * (1) it is declared deferred or - * (2) it is abstract override and its super symbol in `base' is - * nonexistent or incomplete. - * - * @param base ... - * @return ... - */ - final def isIncompleteIn(base: Symbol): Boolean = - this.isDeferred || - (this hasFlag ABSOVERRIDE) && { - val supersym = superSymbol(base) - supersym == NoSymbol || supersym.isIncompleteIn(base) - } - - // Does not always work if the rawInfo is a SourcefileLoader, see comment - // in "def coreClassesFirst" in Global. - final def exists: Boolean = - this != NoSymbol && (!owner.isPackageClass || { rawInfo.load(this); rawInfo != NoType }) - - final def isInitialized: Boolean = - validTo != NoPeriod - - final def isStableClass: Boolean = { - def hasNoAbstractTypeMember(clazz: Symbol): Boolean = - (clazz hasFlag STABLE) || { - var e = clazz.info.decls.elems - while ((e ne null) && !(e.sym.isAbstractType && info.member(e.sym.name) == e.sym)) - e = e.next - e == null - } - def checkStable() = - (info.baseClasses forall hasNoAbstractTypeMember) && { setFlag(STABLE); true } - isClass && (hasFlag(STABLE) || checkStable()) - } - - - /** The variance of this symbol as an integer */ - final def variance: Int = - if (isCovariant) 1 - else if (isContravariant) -1 - else 0 - -// Flags, owner, and name attributes -------------------------------------------------------------- - - def owner: Symbol = rawowner - override final def owner_=(owner: Symbol) { - if (originalOwner contains this) () - else originalOwner(this) = rawowner - - rawowner = owner - } - private[Symbols] def flattenName(): Name = { - // TODO: this assertion causes me a lot of trouble in the interpeter in situations - // where everything proceeds smoothly if there's no assert. I don't think calling "name" - // on a symbol is the right place to throw fatal exceptions if things don't look right. - // It really hampers exploration. - assert(rawowner.isClass, "fatal: %s has non-class owner %s after flatten.".format(rawname + idString, rawowner)) - nme.flattenedName(rawowner.name, rawname) - } - - def ownerChain: List[Symbol] = this :: owner.ownerChain - def enclClassChain: List[Symbol] = { - if (this eq NoSymbol) Nil - else if (isClass && !isPackageClass) this :: owner.enclClassChain - else owner.enclClassChain - } - - def ownersIterator: Iterator[Symbol] = new Iterator[Symbol] { - private var current = Symbol.this - def hasNext = current ne NoSymbol - def next = { val r = current; current = current.owner; r } - } - - /** same as ownerChain contains sym, but more efficient, and - * with a twist for refinement classes. A refinement class - * has a transowner X if an of its parents has transowner X. - */ - def hasTransOwner(sym: Symbol): Boolean = { - var o = this - while ((o ne sym) && (o ne NoSymbol)) o = o.owner - (o eq sym) || - isRefinementClass && (info.parents exists (_.typeSymbol.hasTransOwner(sym))) - } - - def name: Name = rawname - - final def name_=(name: Name) { - if (name != rawname) { - if (owner.isClass) { - var ifs = owner.infos - while (ifs != null) { - ifs.info.decls.rehash(this, name) - ifs = ifs.prev - } - } - rawname = name - } - } - - /** If this symbol has an expanded name, its original name, otherwise its name itself. - * @see expandName - */ - def originalName = nme.originalName(name) - - final def flags: Long = { - val fs = rawflags & phase.flagMask - (fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift) - } - override final def flags_=(fs: Long) = rawflags = fs - final def setFlag(mask: Long): this.type = { rawflags = rawflags | mask; this } - final def resetFlag(mask: Long): this.type = { rawflags = rawflags & ~mask; this } - final def getFlag(mask: Long): Long = flags & mask - final def resetFlags() { rawflags = rawflags & TopLevelCreationFlags } - - /** The class or term up to which this symbol is accessible, - * or RootClass if it is public. - */ - def accessBoundary(base: Symbol): Symbol = { - if (hasFlag(PRIVATE) || isLocal) owner - else if (hasAccessBoundary && !phase.erasedTypes) privateWithin - else if (hasFlag(PROTECTED)) base - else RootClass - } - - def isLessAccessibleThan(other: Symbol): Boolean = { - val tb = this.accessBoundary(owner) - val ob1 = other.accessBoundary(owner) - val ob2 = ob1.linkedClassOfClass - var o = tb - while (o != NoSymbol && o != ob1 && o != ob2) { - o = o.owner - } - o != NoSymbol && o != tb - } - -// Info and Type ------------------------------------------------------------------- - - private[Symbols] var infos: TypeHistory = null - - /** Get type. The type of a symbol is: - * for a type symbol, the type corresponding to the symbol itself, - * @M you should use tpeHK for a type symbol with type parameters if - * the kind of the type need not be *, as tpe introduces dummy arguments - * to generate a type of kind * - * for a term symbol, its usual type - */ - override def tpe: Type = info - - /** Get type info associated with symbol at current phase, after - * ensuring that symbol is initialized (i.e. type is completed). - */ - override def info: Type = try { - // Eugene: insert same thread assertion here - var cnt = 0 - while (validTo == NoPeriod) { - //if (settings.debug.value) System.out.println("completing " + this);//DEBUG - assert(infos ne null, this.name) - assert(infos.prev eq null, this.name) - val tp = infos.info - //if (settings.debug.value) System.out.println("completing " + this.rawname + tp.getClass());//debug - - if ((rawflags & LOCKED) != 0L) { // rolled out once for performance - lock { - setInfo(ErrorType) - throw CyclicReference(this, tp) - } - } else { - rawflags |= LOCKED -// activeLocks += 1 - // lockedSyms += this - } - val current = phase - try { - phase = phaseOf(infos.validFrom) - tp.complete(this) - } finally { - unlock() - phase = current - } - cnt += 1 - // allow for two completions: - // one: sourceCompleter to LazyType, two: LazyType to completed type - if (cnt == 3) abort("no progress in completing " + this + ":" + tp) - } - val result = rawInfo - result - } catch { - case ex: CyclicReference => - if (settings.debug.value) println("... trying to complete "+this) - throw ex - } - - override def info_=(info: Type) { - assert(info ne null) - infos = TypeHistory(currentPeriod, info, null) - unlock() - validTo = if (info.isComplete) currentPeriod else NoPeriod - } - - /** Set initial info. */ - def setInfo(info: Type): this.type = { info_=(info); this } - - def setInfoOwnerAdjusted(info: Type): this.type = setInfo(info.atOwner(this)) - - /** Set new info valid from start of this phase. */ - final def updateInfo(info: Type): Symbol = { - assert(phaseId(infos.validFrom) <= phase.id) - if (phaseId(infos.validFrom) == phase.id) infos = infos.prev - infos = TypeHistory(currentPeriod, info, infos) - validTo = if (info.isComplete) currentPeriod else NoPeriod - this - } - - def hasRawInfo: Boolean = infos ne null - - /** Return info without checking for initialization or completing */ - def rawInfo: Type = { - var infos = this.infos - assert(infos != null) - val curPeriod = currentPeriod - val curPid = phaseId(curPeriod) - - if (validTo != NoPeriod) { - // skip any infos that concern later phases - while (curPid < phaseId(infos.validFrom) && infos.prev != null) - infos = infos.prev - - if (validTo < curPeriod) { - // adapt any infos that come from previous runs - val current = phase - try { - infos = adaptInfos(infos) - - //assert(runId(validTo) == currentRunId, name) - //assert(runId(infos.validFrom) == currentRunId, name) - - if (validTo < curPeriod) { - var itr = infoTransformers.nextFrom(phaseId(validTo)) - infoTransformers = itr; // caching optimization - while (itr.pid != NoPhase.id && itr.pid < current.id) { - phase = phaseWithId(itr.pid) - val info1 = itr.transform(this, infos.info) - if (info1 ne infos.info) { - infos = TypeHistory(currentPeriod + 1, info1, infos) - this.infos = infos - } - validTo = currentPeriod + 1 // to enable reads from same symbol during info-transform - itr = itr.next - } - validTo = if (itr.pid == NoPhase.id) curPeriod - else period(currentRunId, itr.pid) - } - } finally { - phase = current - } - } - } - infos.info - } - - // adapt to new run in fsc. - private def adaptInfos(infos: TypeHistory): TypeHistory = - if (infos == null || runId(infos.validFrom) == currentRunId) { - infos - } else { - val prev1 = adaptInfos(infos.prev) - if (prev1 ne infos.prev) prev1 - else { - def adaptToNewRun(info: Type): Type = - if (isPackageClass) info else adaptToNewRunMap(info) - val pid = phaseId(infos.validFrom) - validTo = period(currentRunId, pid) - phase = phaseWithId(pid) - val info1 = adaptToNewRun(infos.info) - if (info1 eq infos.info) { - infos.validFrom = validTo - infos - } else { - this.infos = TypeHistory(validTo, info1, prev1) - this.infos - } - } - } - - /** Initialize the symbol */ - final def initialize: this.type = { - if (!isInitialized) info - this - } - - /** Was symbol's type updated during given phase? */ - final def isUpdatedAt(pid: Phase#Id): Boolean = { - var infos = this.infos - while ((infos ne null) && phaseId(infos.validFrom) != pid + 1) infos = infos.prev - infos ne null - } - - /** Was symbol's type updated during given phase? */ - final def hasTypeAt(pid: Phase#Id): Boolean = { - var infos = this.infos - while ((infos ne null) && phaseId(infos.validFrom) > pid) infos = infos.prev - infos ne null - } - - /** Modify term symbol's type so that a raw type C is converted to an existential C[_] - * - * This is done in checkAccessible and overriding checks in refchecks - * We can't do this on class loading because it would result in infinite cycles. - */ - final def cookJavaRawInfo() { - if (hasFlag(TRIEDCOOKING)) return else setFlag(TRIEDCOOKING) // only try once... - val oldInfo = info - doCookJavaRawInfo() - } - - protected def doCookJavaRawInfo(): Unit - - - /** The type constructor of a symbol is: - * For a type symbol, the type corresponding to the symbol itself, - * excluding parameters. - * Not applicable for term symbols. - */ - def typeConstructor: Type = - abort("typeConstructor inapplicable for " + this) - - /** @M -- tpe vs tpeHK: - * Symbol::tpe creates a TypeRef that has dummy type arguments to get a type of kind * - * Symbol::tpeHK creates a TypeRef without type arguments, but with type params --> higher-kinded if non-empty list of tpars - * calling tpe may hide errors or introduce spurious ones - * (e.g., when deriving a type from the symbol of a type argument that must be higher-kinded) - * as far as I can tell, it only makes sense to call tpe in conjunction with a substitution that replaces the generated dummy type arguments by their actual types - */ - def tpeHK = if (isType) typeConstructor else tpe // @M! used in memberType - - /** The type parameters of this symbol, without ensuring type completion. - * assumption: if a type starts out as monomorphic, it will not acquire - * type parameters later. - */ - def unsafeTypeParams: List[Symbol] = - if (isMonomorphicType) List() - else { - val current = phase - try { - while ((phase.prev ne NoPhase) && phase.prev.keepsTypeParams) phase = phase.prev - if (phase ne current) phase = phase.next - if (settings.debug.value && settings.verbose.value && (phase ne current)) - log("checking unsafeTypeParams(" + this + ") at: " + current + " reading at: " + phase) - rawInfo.typeParams - } finally { - phase = current - } - } - - /** The type parameters of this symbol. - * assumption: if a type starts out as monomorphic, it will not acquire - * type parameters later. - */ - def typeParams: List[Symbol] = - if (isMonomorphicType) - List() - else { - if (validTo == NoPeriod) { - val current = phase - try { - phase = phaseOf(infos.validFrom) - rawInfo.load(this) - } finally { - phase = current - } - } - rawInfo.typeParams - } - - /** The value parameter sections of this symbol. - */ - def paramss: List[List[Symbol]] = info.paramss - def hasParamWhich(cond: Symbol => Boolean) = paramss exists (_ exists cond) - - /** The least proper supertype of a class; includes all parent types - * and refinement where needed. You need to compute that in a situation like this: - * { - * class C extends P { ... } - * new C - * } - */ - def classBound: Type = { - val tp = refinedType(info.parents, owner) - val thistp = tp.typeSymbol.thisType - val oldsymbuf = new ListBuffer[Symbol] - val newsymbuf = new ListBuffer[Symbol] - for (sym <- info.decls.toList) { - // todo: what about public references to private symbols? - if (sym.isPublic && !sym.isConstructor) { - oldsymbuf += sym - newsymbuf += ( - if (sym.isClass) - tp.typeSymbol.newAbstractType(sym.pos, sym.name.toTypeName).setInfo(sym.existentialBound) - else - sym.cloneSymbol(tp.typeSymbol)) - } - } - val oldsyms = oldsymbuf.toList - val newsyms = newsymbuf.toList - for (sym <- newsyms) { - addMember(thistp, tp, sym.setInfo(sym.info.substThis(this, thistp).substSym(oldsyms, newsyms))) - } - tp - } - - /** If we quantify existentially over this symbol, - * the bound of the type variable that stands for it - * pre: symbol is a term, a class, or an abstract type (no alias type allowed) - */ - def existentialBound: Type = - if (this.isClass) - polyType(this.typeParams, TypeBounds.upper(this.classBound)) - else if (this.isAbstractType) - this.info - else if (this.isTerm) - TypeBounds.upper(intersectionType(List(this.tpe, SingletonClass.tpe))) - else - abort("unexpected alias type: "+this) - - /** Reset symbol to initial state - */ - def reset(completer: Type) { - resetFlags - infos = null - validTo = NoPeriod - //limit = NoPhase.id - setInfo(completer) - } - - /** - * Adds the interface scala.Serializable to the parents of a ClassInfoType. - * Note that the tree also has to be updated accordingly. - */ - def makeSerializable() { - info match { - case ci @ ClassInfoType(_, _, _) => - updateInfo(ci.copy(parents = ci.parents ::: List(SerializableClass.tpe))) - case i => - abort("Only ClassInfoTypes can be made serializable: "+ i) - } - } - -// Comparisons ---------------------------------------------------------------- - - /** A total ordering between symbols that refines the class - * inheritance graph (i.e. subclass.isLess(superclass) always holds). - * the ordering is given by: (_.isType, -_.baseTypeSeq.length) for type symbols, followed by `id'. - */ - final def isLess(that: Symbol): Boolean = { - def baseTypeSeqLength(sym: Symbol) = - if (sym.isAbstractType) 1 + sym.info.bounds.hi.baseTypeSeq.length - else sym.info.baseTypeSeq.length - if (this.isType) - (that.isType && - { val diff = baseTypeSeqLength(this) - baseTypeSeqLength(that) - diff > 0 || diff == 0 && this.id < that.id }) - else - that.isType || this.id < that.id - } - - /** A partial ordering between symbols. - * (this isNestedIn that) holds iff this symbol is defined within - * a class or method defining that symbol - */ - final def isNestedIn(that: Symbol): Boolean = - owner == that || owner != NoSymbol && (owner isNestedIn that) - - /** Is this class symbol a subclass of that symbol? */ - final def isNonBottomSubClass(that: Symbol): Boolean = - this == that || this.isError || that.isError || - info.baseTypeIndex(that) >= 0 - - final def isSubClass(that: Symbol): Boolean = { - isNonBottomSubClass(that) || - this == NothingClass || - this == NullClass && - (that == AnyClass || - that != NothingClass && (that isSubClass AnyRefClass)) - } - final def isNumericSubClass(that: Symbol): Boolean = - definitions.isNumericSubClass(this, that) - -// Overloaded Alternatives --------------------------------------------------------- - - def alternatives: List[Symbol] = - if (hasFlag(OVERLOADED)) info.asInstanceOf[OverloadedType].alternatives - else List(this) - - def filter(cond: Symbol => Boolean): Symbol = - if (hasFlag(OVERLOADED)) { - //assert(info.isInstanceOf[OverloadedType], "" + this + ":" + info);//DEBUG - val alts = alternatives - val alts1 = alts filter cond - if (alts1 eq alts) this - else if (alts1.isEmpty) NoSymbol - else if (alts1.tail.isEmpty) alts1.head - else owner.newOverloaded(info.prefix, alts1) - } else if (this == NoSymbol || cond(this)) { - this - } else NoSymbol - - def suchThat(cond: Symbol => Boolean): Symbol = { - val result = filter(cond) - assert(!(result hasFlag OVERLOADED), result.alternatives) - result - } - -// Cloneing ------------------------------------------------------------------- - - /** A clone of this symbol */ - final def cloneSymbol: Symbol = - cloneSymbol(owner) - - /** A clone of this symbol, but with given owner */ - final def cloneSymbol(owner: Symbol): Symbol = { - val newSym = cloneSymbolImpl(owner) - newSym.privateWithin = privateWithin - newSym.setInfo(info.cloneInfo(newSym)) - .setFlag(this.rawflags).setAnnotations(this.annotations) - } - - /** Internal method to clone a symbol's implementation without flags or type - */ - def cloneSymbolImpl(owner: Symbol): Symbol - -// Access to related symbols -------------------------------------------------- - - /** The primary constructor of a class */ - def primaryConstructor: Symbol = { - var c = info.decl( - if (isTrait || isImplClass) nme.MIXIN_CONSTRUCTOR - else nme.CONSTRUCTOR) - c = if (c hasFlag OVERLOADED) c.alternatives.head else c - //assert(c != NoSymbol) - c - } - - /** The self symbol of a class with explicit self type, or else the - * symbol itself. - */ - def thisSym: Symbol = this - - /** The type of `this' in a class, or else the type of the symbol itself. */ - def typeOfThis = thisSym.tpe - - /** If symbol is a class, the type <code>this.type</code> in this class, - * otherwise <code>NoPrefix</code>. - * We always have: thisType <:< typeOfThis - */ - def thisType: Type = NoPrefix - - /** Return every accessor of a primary constructor parameter in this case class. - * The scope declarations may be out of order because fields with less than private - * access are first given a regular getter, then a new renamed getter which comes - * later in the declaration list. For this reason we have to pinpoint the - * right accessors by starting with the original fields (which will be in the right - * order) and looking for getters with applicable names. The getters may have the - * standard name "foo" or may have been renamed to "foo$\d+" in SyntheticMethods. - * See ticket #1373. - */ - final def caseFieldAccessors: List[Symbol] = { - val allWithFlag = info.decls.toList filter (_.isCaseAccessor) - val (accessors, fields) = allWithFlag partition (_.isMethod) - - def findAccessor(field: Symbol): Symbol = { - // There is another renaming the field may have undergone, for instance as in - // ticket #2175: case class Property[T](private var t: T), t becomes Property$$t. - // So we use the original name everywhere. - val getterName = nme.getterName(field.originalName) - - // Note this is done in two passes intentionally, to ensure we pick up the original - // getter if present before looking for the renamed getter. - def origGetter = accessors find (_.originalName == getterName) - def renamedGetter = accessors find (_.originalName startsWith (getterName + "$")) - val accessorName = origGetter orElse renamedGetter - - // This fails more gracefully rather than throw an Error as it used to because - // as seen in #2625, we can reach this point with an already erroneous tree. - accessorName getOrElse NoSymbol - // throw new Error("Could not find case accessor for %s in %s".format(field, this)) - } - - fields map findAccessor - } - - final def constrParamAccessors: List[Symbol] = - info.decls.toList filter (sym => !sym.isMethod && sym.isParamAccessor) - - /** The symbol accessed by this accessor (getter or setter) function. */ - final def accessed: Symbol = accessed(owner.info) - - /** The symbol accessed by this accessor function, but with given owner type */ - final def accessed(ownerTp: Type): Symbol = { - assert(hasAccessorFlag) - ownerTp.decl(nme.getterToLocal(if (isSetter) nme.setterToGetter(name) else name)) - } - - /** The implementation class of a trait */ - final def implClass: Symbol = owner.info.decl(nme.implClassName(name)) - - /** The class that is logically an outer class of given `clazz'. - * This is the enclosing class, except for classes defined locally to constructors, - * where it is the outer class of the enclosing class - */ - final def outerClass: Symbol = - if (owner.isClass) owner - else if (isClassLocalToConstructor) owner.enclClass.outerClass - else owner.outerClass - - /** For a paramaccessor: a superclass paramaccessor for which this symbol - * is an alias, NoSymbol for all others - */ - def alias: Symbol = NoSymbol - - /** For a lazy value, its lazy accessor. NoSymbol for all others */ - def lazyAccessor: Symbol = NoSymbol - - /** If this is a lazy value, the lazy accessor; otherwise this symbol. */ - def lazyAccessorOrSelf: Symbol = if (isLazy) lazyAccessor else this - - /** For an outer accessor: The class from which the outer originates. - * For all other symbols: NoSymbol - */ - def outerSource: Symbol = NoSymbol - - /** The superclass of this class */ - def superClass: Symbol = if (info.parents.isEmpty) NoSymbol else info.parents.head.typeSymbol - - /** The directly or indirectly inherited mixins of this class - * except for mixin classes inherited by the superclass. Mixin classes appear - * in linearization order. - */ - def mixinClasses: List[Symbol] = { - val sc = superClass - ancestors takeWhile (sc ne) - } - - /** All directly or indirectly inherited classes. - */ - def ancestors: List[Symbol] = info.baseClasses drop 1 - - /** The package class containing this symbol, or NoSymbol if there - * is not one. */ - def enclosingPackageClass: Symbol = - if (this == NoSymbol) this else { - var packSym = this.owner - while (packSym != NoSymbol && !packSym.isPackageClass) - packSym = packSym.owner - packSym - } - - /** The package containing this symbol, or NoSymbol if there - * is not one. */ - def enclosingPackage: Symbol = { - val packSym = enclosingPackageClass - if (packSym != NoSymbol) packSym.companionModule - else packSym - } - - /** Return the original enclosing method of this symbol. It should return - * the same thing as enclMethod when called before lambda lift, - * but it preserves the original nesting when called afterwards. - */ - def originalEnclosingMethod: Symbol = { - if (isMethod) this - else { - val owner = originalOwner.getOrElse(this, rawowner) - if (isLocalDummy) owner.enclClass.primaryConstructor - else owner.originalEnclosingMethod - } - } - - /** The method or class which logically encloses the current symbol. - * If the symbol is defined in the initialization part of a template - * this is the template's primary constructor, otherwise it is - * the physically enclosing method or class. - * - * Example 1: - * - * def f() { val x = { def g() = ...; g() } } - * - * In this case the owner chain of `g' is `x', followed by `f' and - * `g.logicallyEnclosingMember == f`. - * - * Example 2: - * - * class C { - * def <init> = { ... } - * val x = { def g() = ...; g() } } - * } - * - * In this case the owner chain of `g' is `x', followed by `C' but - * g.logicallyEnclosingMember is the primary constructor symbol `<init>' - * (or, for traits: `$init') of `C'. - * - */ - def logicallyEnclosingMember: Symbol = - if (isLocalDummy) enclClass.primaryConstructor - else if (isMethod || isClass) this - else owner.logicallyEnclosingMember - - /** The top-level class containing this symbol */ - def toplevelClass: Symbol = - if (owner.isPackageClass) { - if (isClass) this else moduleClass - } else owner.toplevelClass - - /** Is this symbol defined in the same scope and compilation unit as `that' symbol? - */ - def isCoDefinedWith(that: Symbol) = ( - (this.rawInfo ne NoType) && - (this.owner == that.owner) && { - !this.owner.isPackageClass || - (this.sourceFile eq null) || - (that.sourceFile eq null) || - (this.sourceFile == that.sourceFile) || { - // recognize companion object in separate file and fail, else compilation - // appears to succeed but highly opaque errors come later: see bug #1286 - if (this.sourceFile.path != that.sourceFile.path) - throw InvalidCompanions(this, that) - - false - } - } - ) - - /** The internal representation of classes and objects: - * - * class Foo is "the class" or sometimes "the plain class" - * object Foo is "the module" - * class Foo$ is "the module class" (invisible to the user: it implements object Foo) - * - * class Foo < - * ^ ^ (2) \ - * | | | \ - * | (5) | (3) - * | | | \ - * (1) v v \ - * object Foo (4)-> > class Foo$ - * - * (1) companionClass - * (2) companionModule - * (3) linkedClassOfClass - * (4) moduleClass - * (5) companionSymbol - */ - - /** For a module or case factory: the class with the same name in the same package. - * For all others: NoSymbol - * Note: does not work for classes owned by methods, see Namers.companionClassOf - * - * object Foo . companionClass --> class Foo - */ - final def companionClass: Symbol = { - if (this != NoSymbol) - flatOwnerInfo.decl(name.toTypeName).suchThat(_ isCoDefinedWith this) - else NoSymbol - } - - /** A helper method that factors the common code used the discover a - * companion module of a class. If a companion module exists, its symbol is - * returned, otherwise, `NoSymbol` is returned. The method assumes that - * `this` symbol has already been checked to be a class (using `isClass`). - */ - private final def companionModule0: Symbol = - flatOwnerInfo.decl(name.toTermName).suchThat( - sym => sym.hasFlag(MODULE) && (sym isCoDefinedWith this) && !sym.isMethod) - - /** For a class: the module or case class factory with the same name in the same package. - * For all others: NoSymbol - * Note: does not work for modules owned by methods, see Namers.companionModuleOf - * - * class Foo . companionModule --> object Foo - */ - final def companionModule: Symbol = - if (isClass && !isRefinementClass) companionModule0 - else NoSymbol - - /** For a module: its linked class - * For a plain class: its linked module or case factory. - * Note: does not work for modules owned by methods, see Namers.companionSymbolOf - * - * class Foo <-- companionSymbol --> object Foo - */ - final def companionSymbol: Symbol = - if (isTerm) companionClass - else if (isClass) companionModule0 - else NoSymbol - - /** For a module class: its linked class - * For a plain class: the module class of its linked module. - * - * class Foo <-- linkedClassOfClass --> class Foo$ - */ - final def linkedClassOfClass: Symbol = - if (isModuleClass) companionClass else companionModule.moduleClass - - /** - * Returns the rawInfo of the owner. If the current phase has flat classes, - * it first applies all pending type maps to this symbol. - * - * assume this is the ModuleSymbol for B in the following definition: - * package p { class A { object B { val x = 1 } } } - * - * The owner after flatten is "package p" (see "def owner"). The flatten type map enters - * symbol B in the decls of p. So to find a linked symbol ("object B" or "class B") - * we need to apply flatten to B first. Fixes #2470. - */ - private final def flatOwnerInfo: Type = { - if (needsFlatClasses) - info - owner.rawInfo - } - - /** If this symbol is an implementation class, its interface, otherwise the symbol itself - * The method follows two strategies to determine the interface. - * - during or after erasure, it takes the last parent of the implementation class - * (which is always the interface, by convention) - * - before erasure, it looks up the interface name in the scope of the owner of the class. - * This only works for implementation classes owned by other classes or traits. - */ - final def toInterface: Symbol = - if (isImplClass) { - val result = - if (phase.next.erasedTypes) { - assert(!tpe.parents.isEmpty, this) - tpe.parents.last.typeSymbol - } else { - owner.info.decl(nme.interfaceName(name)) - } - assert(result != NoSymbol, this) - result - } else this - - /** The module class corresponding to this module. - */ - def moduleClass: Symbol = NoSymbol - - /** The non-private symbol whose type matches the type of this symbol - * in in given class. - * - * @param ofclazz The class containing the symbol's definition - * @param site The base type from which member types are computed - */ - final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol = - ofclazz.info.nonPrivateDecl(name).filter(sym => - !sym.isTerm || (site.memberType(this) matches site.memberType(sym))) - - /** The non-private member of `site' whose type and name match the type of this symbol - */ - final def matchingSymbol(site: Type, admit: Long = 0L): Symbol = - site.nonPrivateMemberAdmitting(name, admit).filter(sym => - !sym.isTerm || (site.memberType(this) matches site.memberType(sym))) - - /** The symbol overridden by this symbol in given class `ofclazz'. - * @pre 'ofclazz' is a base class of this symbol's owner. - */ - final def overriddenSymbol(ofclazz: Symbol): Symbol = - if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, owner.thisType) - - /** The symbol overriding this symbol in given subclass `ofclazz' - * @pre: `ofclazz' is a subclass of this symbol's owner - */ - final def overridingSymbol(ofclazz: Symbol): Symbol = - if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, ofclazz.thisType) - - /** Returns all symbols overriden by this symbol - */ - final def allOverriddenSymbols: List[Symbol] = - if (!owner.isClass) Nil - else owner.ancestors map overriddenSymbol filter (_ != NoSymbol) - - /** Returns all symbols overridden by this symbol, plus all matching symbols - * defined in parents of the selftype - */ - final def extendedOverriddenSymbols: List[Symbol] = - if (!owner.isClass) Nil - else owner.thisSym.ancestors map overriddenSymbol filter (_ != NoSymbol) - - /** The symbol accessed by a super in the definition of this symbol when - * seen from class `base'. This symbol is always concrete. - * pre: `this.owner' is in the base class sequence of `base'. - */ - final def superSymbol(base: Symbol): Symbol = { - var bcs = base.info.baseClasses.dropWhile(owner !=).tail - var sym: Symbol = NoSymbol - while (!bcs.isEmpty && sym == NoSymbol) { - if (!bcs.head.isImplClass) - sym = matchingSymbol(bcs.head, base.thisType).suchThat(!_.isDeferred) - bcs = bcs.tail - } - sym - } - - /** The getter of this value or setter definition in class `base', or NoSymbol if - * none exists. - */ - final def getter(base: Symbol): Symbol = { - val getterName = if (isSetter) nme.setterToGetter(name) else nme.getterName(name) - base.info.decl(getterName) filter (_.hasAccessorFlag) - } - - /** The setter of this value or getter definition, or NoSymbol if none exists */ - final def setter(base: Symbol): Symbol = setter(base, false) - - final def setter(base: Symbol, hasExpandedName: Boolean): Symbol = { - var sname = nme.getterToSetter(nme.getterName(name)) - if (hasExpandedName) sname = nme.expandedSetterName(sname, base) - base.info.decl(sname) filter (_.hasAccessorFlag) - } - - /** The case module corresponding to this case class - * @pre case class is a member of some other class or package - */ - final def caseModule: Symbol = { - var modname = name.toTermName - if (privateWithin.isClass && !privateWithin.isModuleClass && !hasFlag(EXPANDEDNAME)) - modname = nme.expandedName(modname, privateWithin) - initialize.owner.info.decl(modname).suchThat(_.isModule) - } - - /** If this symbol is a type parameter skolem (not an existential skolem!) - * its corresponding type parameter, otherwise this */ - def deSkolemize: Symbol = this - - /** If this symbol is an existential skolem the location (a Tree or null) - * where it was unpacked. Resulttype is AnyRef because trees are not visible here. */ - def unpackLocation: AnyRef = null - - /** Remove private modifier from symbol `sym's definition. If `sym' is a - * term symbol rename it by expanding its name to avoid name clashes - */ - final def makeNotPrivate(base: Symbol) { - if (this hasFlag PRIVATE) { - setFlag(notPRIVATE) - if (isMethod && !isDeferred) setFlag(lateFINAL) - if (!isStaticModule && !isClassConstructor) { - expandName(base) - if (isModule) moduleClass.makeNotPrivate(base) - } - } - } - - /** change name by appending $$<fully-qualified-name-of-class `base'> - * Do the same for any accessed symbols or setters/getters - */ - def expandName(base: Symbol) { - if (this.isTerm && this != NoSymbol && !hasFlag(EXPANDEDNAME)) { - setFlag(EXPANDEDNAME) - if (hasAccessorFlag && !isDeferred) { - accessed.expandName(base) - } else if (hasGetter) { - getter(owner).expandName(base) - setter(owner).expandName(base) - } - name = nme.expandedName(name, base) - if (isType) name = name - } - } -/* code for fixing nested objects - def expandModuleClassName() { - name = newTypeName(name.toString + "$") - } - - def isExpandedModuleClass: Boolean = name(name.length - 1) == '$' -*/ - def sourceFile: AbstractFile = - if (isModule) moduleClass.sourceFile - else toplevelClass.sourceFile - - def sourceFile_=(f: AbstractFile) { - abort("sourceFile_= inapplicable for " + this) - } - - /** If this is a sealed class, its known direct subclasses. - * Otherwise, the empty set. - */ - def children: Set[Symbol] = Set() - - /** Recursively assemble all children of this symbol. - */ - def sealedDescendants: Set[Symbol] = children.flatMap(_.sealedDescendants) + this - -// ToString ------------------------------------------------------------------- - - /** A tag which (in the ideal case) uniquely identifies class symbols */ - final def tag = fullName.## - - /** The simple name of this Symbol */ - final def simpleName: Name = name - - /** The String used to order otherwise identical sealed symbols. - * This uses data which is stable across runs and variable classpaths - * (the initial Name) before falling back on id, which varies depending - * on exactly when a symbol is loaded. - */ - final def sealedSortName = initName + "#" + id - - /** String representation of symbol's definition key word */ - final def keyString: String = - if (isJavaInterface) "interface" - else if (isTrait) "trait" - else if (isClass) "class" - else if (isType && !isParameter) "type" - else if (isVariable) "var" - else if (isPackage) "package" - else if (isModule) "object" - else if (isSourceMethod) "def" - else if (isTerm && (!isParameter || isParamAccessor)) "val" - else "" - - /** Accurate string representation of symbols' kind, suitable for developers. */ - final def accurateKindString: String = - if (isPackage) "package" - else if (isPackageClass) "package class" - else if (isPackageObject) "package object" - else if (isPackageObjectClass) "package object class" - else if (isRefinementClass) "refinement class" - else if (isModule) "module" - else if (isModuleClass) "module class" - else sanitizedKindString - - /** String representation of symbol's kind, suitable for the masses. */ - private def sanitizedKindString: String = - if (isPackage || isPackageClass) "package" - else if (isModule || isModuleClass) "object" - else if (isAnonymousClass) "anonymous class" - else if (isRefinementClass) "" - else if (isTrait) "trait" - else if (isClass) "class" - else if (isType) "type" - else if (isTerm && isLazy) "lazy value" - else if (isVariable) "variable" - else if (isClassConstructor) "constructor" - else if (isSourceMethod) "method" - else if (isTerm) "value" - else "" - - final def kindString: String = - if (settings.debug.value) accurateKindString - else sanitizedKindString - - /** If the name of the symbol's owner should be used when you care about - * seeing an interesting name: in such cases this symbol is e.g. a method - * parameter with a synthetic name, a constructor named "this", an object - * "package", etc. The kind string, if non-empty, will be phrased relative - * to the name of the owner. - */ - def hasMeaninglessName = ( - isSetterParameter // x$1 - || isClassConstructor // this - || isPackageObject // package - || isPackageObjectClass // package$ - || isRefinementClass // <refinement> - ) - - /** String representation of symbol's simple name. - * If !settings.debug translates expansions of operators back to operator symbol. - * E.g. $eq => =. - * If settings.uniqid, adds id. - */ - def nameString = decodedName + idString - - /** If settings.uniqid is set, the symbol's id, else "" */ - final def idString = if (settings.uniqid.value) "#"+id else "" - - /** String representation, including symbol's kind e.g., "class Foo", "method Bar". - * If hasMeaninglessName is true, uses the owner's name to disambiguate identity. - */ - override def toString = compose( - kindString, - if (hasMeaninglessName) owner.nameString else nameString - ) - - /** String representation of location. - */ - def ownsString = { - val owns = owner.skipPackageObject - if (owns.isClass && !owns.printWithoutPrefix && !isScalaPackageClass) "" + owns - else "" - } - - /** String representation of location, plus a preposition. Doesn't do much, - * for backward compatibility reasons. - */ - def locationString = ownsString match { - case "" => "" - case s => " in " + s - } - def fullLocationString = toString + locationString - - /** String representation of symbol's definition following its name */ - final def infoString(tp: Type): String = { - def typeParamsString: String = tp match { - case PolyType(tparams, _) if tparams.nonEmpty => - (tparams map (_.defString)).mkString("[", ",", "]") - case _ => - "" - } - if (isClass) - typeParamsString + " extends " + tp.resultType - else if (isAliasType) - typeParamsString + " = " + tp.resultType - else if (isAbstractType) - typeParamsString + { - tp.resultType match { - case TypeBounds(lo, hi) => - (if (lo.typeSymbol == NothingClass) "" else " >: " + lo) + - (if (hi.typeSymbol == AnyClass) "" else " <: " + hi) - case rtp => - "<: " + rtp - } - } - else if (isModule) - moduleClass.infoString(tp) - else - tp match { - case PolyType(tparams, res) => - typeParamsString + infoString(res) - case NullaryMethodType(res) => - infoString(res) - case MethodType(params, res) => - params.map(_.defString).mkString("(", ",", ")") + infoString(res) - case _ => - ": " + tp - } - } - - def infosString = infos.toString() - - def hasFlagsToString(mask: Long): String = flagsToString( - flags & mask, - if (hasAccessBoundary) privateWithin.toString else "" - ) - - /** String representation of symbol's variance */ - def varianceString: String = - if (variance == 1) "+" - else if (variance == -1) "-" - else "" - - def defaultFlagMask = - if (settings.debug.value) -1L - else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE - else ExplicitFlags - - def defaultFlagString = hasFlagsToString(defaultFlagMask) - - /** String representation of symbol's definition */ - def defString = compose( - defaultFlagString, - keyString, - varianceString + nameString + ( - if (hasRawInfo) infoString(rawInfo) else "<_>" - ) - ) - - /** Concatenate strings separated by spaces */ - private def compose(ss: String*) = ss filter (_ != "") mkString " " - - def isSingletonExistential = - nme.isSingletonName(name) && (info.bounds.hi.typeSymbol isSubClass SingletonClass) - - /** String representation of existentially bound variable */ - def existentialToString = - if (isSingletonExistential && !settings.debug.value) - "val " + nme.dropSingletonName(name) + ": " + dropSingletonType(info.bounds.hi) - else defString - } - - /** A class for term symbols */ - class TermSymbol(initOwner: Symbol, initPos: Position, initName: TermName) - extends Symbol(initOwner, initPos, initName) { - final override def isTerm = true - - override def name: TermName = super.name - privateWithin = NoSymbol - - var referenced: Symbol = NoSymbol - - def cloneSymbolImpl(owner: Symbol): Symbol = - new TermSymbol(owner, pos, name).copyAttrsFrom(this) - - def copyAttrsFrom(original: TermSymbol): this.type = { - referenced = original.referenced - this - } - - private val validAliasFlags = SUPERACCESSOR | PARAMACCESSOR | MIXEDIN | SPECIALIZED - - override def alias: Symbol = - if (hasFlag(validAliasFlags)) initialize.referenced - else NoSymbol - - def setAlias(alias: Symbol): TermSymbol = { - assert(alias != NoSymbol, this) - assert(!alias.isOverloaded, alias) - assert(hasFlag(validAliasFlags), this) - - referenced = alias - this - } - - override def outerSource: Symbol = - if (name endsWith nme.OUTER) initialize.referenced - else NoSymbol - - override def moduleClass: Symbol = - if (hasFlag(MODULE)) referenced else NoSymbol - - def setModuleClass(clazz: Symbol): TermSymbol = { - assert(hasFlag(MODULE)) - referenced = clazz - this - } - - def setLazyAccessor(sym: Symbol): TermSymbol = { - assert(isLazy && (referenced == NoSymbol || referenced == sym), this) - referenced = sym - this - } - - override def lazyAccessor: Symbol = { - assert(isLazy, this) - referenced - } - - protected def doCookJavaRawInfo() { - def cook(sym: Symbol) { - require(sym hasFlag JAVA) - // @M: I think this is more desirable, but Martin prefers to leave raw-types as-is as much as possible - // object rawToExistentialInJava extends TypeMap { - // def apply(tp: Type): Type = tp match { - // // any symbol that occurs in a java sig, not just java symbols - // // see http://lampsvn.epfl.ch/trac/scala/ticket/2454#comment:14 - // case TypeRef(pre, sym, List()) if !sym.typeParams.isEmpty => - // val eparams = typeParamsToExistentials(sym, sym.typeParams) - // existentialAbstraction(eparams, TypeRef(pre, sym, eparams map (_.tpe))) - // case _ => - // mapOver(tp) - // } - // } - val tpe1 = rawToExistential(sym.tpe) - // println("cooking: "+ sym +": "+ sym.tpe +" to "+ tpe1) - if (tpe1 ne sym.tpe) { - sym.setInfo(tpe1) - } - } - - if (isJavaDefined) - cook(this) - else if (hasFlag(OVERLOADED)) - for (sym2 <- alternatives) - if (sym2 hasFlag JAVA) - cook(sym2) - } - } - - /** A class for module symbols */ - class ModuleSymbol(initOwner: Symbol, initPos: Position, initName: TermName) - extends TermSymbol(initOwner, initPos, initName) { - private var flatname: TermName = null - // This method could use a better name from someone clearer on what the condition expresses. - private def isFlatAdjusted = !isMethod && needsFlatClasses - - override def owner: Symbol = - if (isFlatAdjusted) rawowner.owner - else rawowner - - override def name: TermName = - if (isFlatAdjusted) { - if (flatname == null) - flatname = flattenName().toTermName - - flatname - } else rawname - - override def cloneSymbolImpl(owner: Symbol): Symbol = - new ModuleSymbol(owner, pos, name).copyAttrsFrom(this) - } - - /** A class for method symbols */ - class MethodSymbol(initOwner: Symbol, initPos: Position, initName: TermName) - extends TermSymbol(initOwner, initPos, initName) { - private var mtpePeriod = NoPeriod - private var mtpePre: Type = _ - private var mtpeResult: Type = _ - private var mtpeInfo: Type = _ - - override def cloneSymbolImpl(owner: Symbol): Symbol = - new MethodSymbol(owner, pos, name).copyAttrsFrom(this) - - def typeAsMemberOf(pre: Type): Type = { - if (mtpePeriod == currentPeriod) { - if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult - } else if (isValid(mtpePeriod)) { - mtpePeriod = currentPeriod - if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult - } - val res = pre.computeMemberType(this) - mtpePeriod = currentPeriod - mtpePre = pre - mtpeInfo = info - mtpeResult = res - res - } - } - - /** A class of type symbols. Alias and abstract types are direct instances - * of this class. Classes are instances of a subclass. - */ - class TypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) - extends Symbol(initOwner, initPos, initName) { - privateWithin = NoSymbol - private var tyconCache: Type = null - private var tyconRunId = NoRunId - private var tpeCache: Type = _ - private var tpePeriod = NoPeriod - - override def name: TypeName = super.name.asInstanceOf[TypeName] - final override def isType = true - override def isNonClassType = true - override def isAbstractType = isDeferred - override def isAliasType = !isDeferred - - private def newTypeRef(targs: List[Type]) = { - val pre = if (hasFlag(PARAM | EXISTENTIAL)) NoPrefix else owner.thisType - typeRef(pre, this, targs) - } - - /** Let's say you have a type definition - * - * type T <: Number - * - * and tsym is the symbol corresponding to T. Then - * - * tsym.info = TypeBounds(Nothing, Number) - * tsym.tpe = TypeRef(NoPrefix, T, List()) - */ - override def tpe: Type = { - if (tpeCache eq NoType) throw CyclicReference(this, typeConstructor) - if (tpePeriod != currentPeriod) { - if (isValid(tpePeriod)) { - tpePeriod = currentPeriod - } else { - if (isInitialized) tpePeriod = currentPeriod - tpeCache = NoType - val targs = - if (phase.erasedTypes && this != ArrayClass) List() - else unsafeTypeParams map (_.typeConstructor) //@M! use typeConstructor to generate dummy type arguments, - // sym.tpe should not be called on a symbol that's supposed to be a higher-kinded type - // memberType should be used instead, that's why it uses tpeHK and not tpe - tpeCache = newTypeRef(targs) - } - } - assert(tpeCache ne null/*, "" + this + " " + phase*/)//debug - tpeCache - } - - // needed for experimental code for early types as type parameters - // def refreshType() { tpePeriod = NoPeriod } - - override def typeConstructor: Type = { - if ((tyconCache eq null) || tyconRunId != currentRunId) { - tyconCache = newTypeRef(Nil) - tyconRunId = currentRunId - } - assert(tyconCache ne null) - tyconCache - } - - override def info_=(tp: Type) { - tpePeriod = NoPeriod - tyconCache = null - super.info_=(tp) - } - - override def reset(completer: Type) { - super.reset(completer) - tpePeriod = NoPeriod - tyconRunId = NoRunId - } - - /*** example: - * public class Test3<T> {} - * public class Test1<T extends Test3> {} - * info for T in Test1 should be >: Nothing <: Test3[_] - */ - protected def doCookJavaRawInfo() { - // don't require isJavaDefined, since T in the above example does not have that flag - val tpe1 = rawToExistential(info) - // println("cooking type: "+ this +": "+ info +" to "+ tpe1) - if (tpe1 ne info) { - setInfo(tpe1) - } - } - - def cloneSymbolImpl(owner: Symbol): Symbol = - new TypeSymbol(owner, pos, name) //.toTypeName) - - incCounter(typeSymbolCount) - } - - /** A class for type parameters viewed from inside their scopes - * - * @param origin Can be either a tree, or a symbol, or null. - * If skolem got created from newTypeSkolem (called in Namers), origin denotes - * the type parameter from which the skolem was created. If it got created from - * skolemizeExistential, origin is either null or a Tree. If it is a Tree, it indicates - * where the skolem was introduced (this is important for knowing when to pack it - * again into ab Existential). origin is `null' only in skolemizeExistentials called - * from <:< or isAsSpecific, because here its value does not matter. - * I elieve the following invariant holds: - * - * origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL) - */ - class TypeSkolem(initOwner: Symbol, initPos: Position, initName: TypeName, origin: AnyRef) - extends TypeSymbol(initOwner, initPos, initName) { - - /** The skolemization level in place when the skolem was constructed */ - val level = skolemizationLevel - - final override def isSkolem = true - - /** If typeskolem comes from a type parameter, that parameter, otherwise skolem itself */ - override def deSkolemize = origin match { - case s: Symbol => s - case _ => this - } - - /** If type skolem comes from an existential, the tree where it was created */ - override def unpackLocation = origin - - override def typeParams = info.typeParams //@M! (not deSkolemize.typeParams!!), also can't leave superclass definition: use info, not rawInfo - - override def cloneSymbolImpl(owner: Symbol): Symbol = - new TypeSkolem(owner, pos, name, origin) - - override def nameString: String = - if (settings.debug.value) (super.nameString + "&" + level) - else super.nameString - } - - - /** A class for class symbols */ - class ClassSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) - extends TypeSymbol(initOwner, initPos, initName) { - - private var source: AbstractFile = null - private var thissym: Symbol = this - - final override def isClass = true - final override def isNonClassType = false - final override def isAbstractType = false - final override def isAliasType = false - - override def sourceFile = - if (owner.isPackageClass) source - else super.sourceFile - override def sourceFile_=(f: AbstractFile) { source = f } - - override def reset(completer: Type) { - super.reset(completer) - thissym = this - } - - private var flatname: TypeName = null - - override def owner: Symbol = - if (needsFlatClasses) rawowner.owner - else rawowner - - override def name: TypeName = - if (needsFlatClasses) { - if (flatname == null) - flatname = flattenName().toTypeName - flatname - } - else rawname.asInstanceOf[TypeName] - - private var thisTypeCache: Type = _ - private var thisTypePeriod = NoPeriod - - private var typeOfThisCache: Type = _ - private var typeOfThisPeriod = NoPeriod - - /** the type this.type in this class */ - override def thisType: Type = { - val period = thisTypePeriod - if (period != currentPeriod) { - thisTypePeriod = currentPeriod - if (!isValid(period)) thisTypeCache = ThisType(this) - } - thisTypeCache - } - - /** A symbol carrying the self type of the class as its type */ - override def thisSym: Symbol = thissym - - /** the self type of an object foo is foo.type, not class<foo>.this.type - */ - override def typeOfThis: Type = { - if (getFlag(MODULE | IMPLCLASS) == MODULE.toLong && owner != NoSymbol) { - val period = typeOfThisPeriod - if (period != currentPeriod) { - typeOfThisPeriod = currentPeriod - if (!isValid(period)) - typeOfThisCache = singleType(owner.thisType, sourceModule) - } - typeOfThisCache - } - else thissym.tpe - } - - /** Sets the self type of the class */ - override def typeOfThis_=(tp: Type) { - thissym = newThisSym(pos).setInfo(tp) - } - - override def cloneSymbolImpl(owner: Symbol): Symbol = { - val clone = new ClassSymbol(owner, pos, name) - if (thisSym != this) { - clone.typeOfThis = typeOfThis - clone.thisSym.name = thisSym.name - } - clone - } - - override def sourceModule = - if (isModuleClass) companionModule else NoSymbol - - private var childSet: Set[Symbol] = Set() - override def children = childSet - override def addChild(sym: Symbol) { childSet = childSet + sym } - - incCounter(classSymbolCount) - } - - /** A class for module class symbols - * Note: Not all module classes are of this type; when unpickled, we get - * plain class symbols! - */ - class ModuleClassSymbol(owner: Symbol, pos: Position, name: TypeName) - extends ClassSymbol(owner, pos, name) { - private var module: Symbol = null - def this(module: TermSymbol) = { - this(module.owner, module.pos, module.name.toTypeName) - setFlag(module.getFlag(ModuleToClassFlags) | MODULE | FINAL) - sourceModule = module - } - override def sourceModule = module - private var implicitMembersCacheValue: List[Symbol] = List() - private var implicitMembersCacheKey: Type = NoType - def implicitMembers: List[Symbol] = { - val tp = info - if (implicitMembersCacheKey ne tp) { - implicitMembersCacheKey = tp - implicitMembersCacheValue = tp.implicitMembers - } - implicitMembersCacheValue - } - override def sourceModule_=(module: Symbol) { this.module = module } - } - - /** An object representing a missing symbol */ - object NoSymbol extends Symbol(null, NoPosition, nme.NO_NAME) { - setInfo(NoType) - privateWithin = this - override def info_=(info: Type) { - infos = TypeHistory(1, NoType, null) - unlock() - validTo = currentPeriod - } - override def defString: String = toString - override def locationString: String = "" - override def enclClass: Symbol = this - override def toplevelClass: Symbol = this - override def enclMethod: Symbol = this - override def owner: Symbol = abort("no-symbol does not have owner") - override def sourceFile: AbstractFile = null - override def ownerChain: List[Symbol] = List() - override def ownersIterator: Iterator[Symbol] = Iterator.empty - override def alternatives: List[Symbol] = List() - override def reset(completer: Type) {} - override def info: Type = NoType - override def rawInfo: Type = NoType - protected def doCookJavaRawInfo() {} - override def accessBoundary(base: Symbol): Symbol = RootClass - def cloneSymbolImpl(owner: Symbol): Symbol = abort() - override def originalEnclosingMethod = this - } - - def cloneSymbols[T <: Symbol](syms: List[T]): List[T] = { - val syms1 = syms map (_.cloneSymbol.asInstanceOf[T]) - for (sym1 <- syms1) sym1.setInfo(sym1.info.substSym(syms, syms1)) - syms1 - } - - def cloneSymbols[T <: Symbol](syms: List[T], owner: Symbol): List[T] = { - val syms1 = syms map (_.cloneSymbol(owner).asInstanceOf[T]) - for (sym1 <- syms1) sym1.setInfo(sym1.info.substSym(syms, syms1)) - syms1 - } - - /** An exception for cyclic references of symbol definitions */ - case class CyclicReference(sym: Symbol, info: Type) - extends TypeError("illegal cyclic reference involving " + sym) { - // printStackTrace() // debug - } - - case class InvalidCompanions(sym1: Symbol, sym2: Symbol) - extends Throwable("Companions '" + sym1 + "' and '" + sym2 + "' must be defined in same file") { - override def toString = getMessage - } - - /** A class for type histories */ - private sealed case class TypeHistory(var validFrom: Period, info: Type, prev: TypeHistory) { - assert((prev eq null) || phaseId(validFrom) > phaseId(prev.validFrom), this) - assert(validFrom != NoPeriod) - override def toString() = - "TypeHistory(" + phaseOf(validFrom)+":"+runId(validFrom) + "," + info + "," + prev + ")" - } -} diff --git a/src/compiler/scala/tools/nsc/symtab/TypeDebugging.scala b/src/compiler/scala/tools/nsc/symtab/TypeDebugging.scala index 62e812704b..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/TypeDebugging.scala +++ b/src/compiler/scala/tools/nsc/symtab/TypeDebugging.scala @@ -1,72 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package symtab - -trait TypeDebugging { - self: SymbolTable => - - import definitions._ - - // @M toString that is safe during debugging (does not normalize, ...) - object TypeDebugStrings { - object str { - def parentheses(xs: List[_]): String = xs.mkString("(", ", ", ")") - def brackets(xs: List[_]): String = if (xs.isEmpty) "" else xs.mkString("[", ", ", "]") - def tparams(tparams: List[Type]): String = brackets(tparams map debug) - def parents(ps: List[Type]): String = (ps map debug).mkString(" with ") - def refine(defs: Scope): String = defs.toList.mkString("{", " ;\n ", "}") - } - - def dump(tp: Type): Unit = { - println("** " + tp + " / " + tp.getClass + " **") - import tp._ - - println("typeSymbol = " + typeSymbol) - println("termSymbol = " + termSymbol) - println("widen = " + widen) - println("deconst = " + deconst) - println("typeOfThis = " + typeOfThis) - println("bounds = " + bounds) - println("parents = " + parents) - println("prefixChain = " + prefixChain) - println("typeConstructor = " + typeConstructor) - println(" .. typeConstructor.typeParams = " + typeConstructor.typeParams) - println(" .. _.variance = " + (typeConstructor.typeParams map (_.variance))) - println("typeArgs = " + typeArgs) - println("resultType = " + resultType) - println("finalResultType = " + finalResultType) - println("paramss = " + paramss) - println("paramTypes = " + paramTypes) - println("typeParams = " + typeParams) - println("boundSyms = " + boundSyms) - println("baseTypeSeq = " + baseTypeSeq) - println("baseClasses = " + baseClasses) - println("toLongString = " + toLongString) - } - - private def debug(tp: Type): String = tp match { - case TypeRef(pre, sym, args) => debug(pre) + "." + sym.nameString + str.tparams(args) - case ThisType(sym) => sym.nameString + ".this" - case SingleType(pre, sym) => debug(pre) +"."+ sym.nameString +".type" - case RefinedType(parents, defs) => str.parents(parents) + str.refine(defs) - case ClassInfoType(parents, defs, clazz) => "class "+ clazz.nameString + str.parents(parents) + str.refine(defs) - case PolyType(tparams, result) => str.brackets(tparams) + " " + debug(result) - case TypeBounds(lo, hi) => ">: "+ debug(lo) +" <: "+ debug(hi) - case tv @ TypeVar(_, _) => tv.toString - case ExistentialType(tparams, qtpe) => "forSome "+ str.brackets(tparams) + " " + debug(qtpe) - case _ => tp.toString - } - def debugString(tp: Type) = debug(tp) - } - private def TDS = TypeDebugStrings - - def paramString(tp: Type) = TDS.str parentheses (tp.params map (_.defString)) - def typeParamsString(tp: Type) = TDS.str brackets (tp.typeParams map (_.defString)) - def typeArgsString(tp: Type) = TDS.str brackets (tp.typeArgs map (_.safeToString)) - def debugString(tp: Type) = TDS debugString tp -} - diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 80a48e55fc..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -1,5674 +0,0 @@ -/* 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 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 - - /** 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' forSome { type T' <: T with Singleton } - * Overridden where we know more about where types come from. - */ - def narrow: Type = - if (phase.erasedTypes) this - else commonOwner(this) freshExistential ".type" setInfo singletonBounds(this) tpe - - /** 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 = - 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 = { - val suspension = TypeVar.Suspension - // 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 - this foreach { - case tv: TypeVar => suspension suspend tv - case _ => () - } - } - - 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) - suspension.resumeAll - 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) - while ((prevEntry ne null) && - !(prevEntry.sym == sym || - prevEntry.sym.owner != sym.owner && - !sym.hasFlag(PRIVATE) && { - if (self eq null) self = this.narrow - self.memberType(prevEntry.sym) matches self.memberType(sym) - })) { - 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) - suspension.resumeAll - 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" - } - - object ThisType extends ThisTypeExtractor { - def apply(sym: Symbol): Type = - if (!phase.erasedTypes) unique(new ThisType(sym) with UniqueType) - else if (sym.isImplClass) sym.typeOfThis - else sym.tpe - } - - /** A class for singleton types of the form <prefix>.<sym.name>.type. - * Cannot be created directly; one should always use - * `singleType' for creation. - */ - 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" - } - - object SingleType extends SingleTypeExtractor - - 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" - } - - object SuperType extends SuperTypeExtractor { - def apply(thistp: Type, supertp: Type): Type = - if (phase.erasedTypes) supertp - else unique(new SuperType(thistp, supertp) with UniqueType) - } - - /** 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" - } - - 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 TypeBounds(lo, hi) with UniqueType) - } - - /** 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 <parents_n> { decls }' - * Cannot be created directly; - * one should always use `refinedType' for creation. - */ - case class RefinedType(override val parents: List[Type], - override val decls: Scope) extends CompoundType { - - override def isHigherKinded = ( - parents.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" - } - - object RefinedType extends RefinedTypeExtractor { - def apply(parents: List[Type], decls: Scope, clazz: Symbol) = - new RefinedType(parents, decls) { override def typeSymbol = 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</pre> - * @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</pre>, for - * all elements <pre>sym</pre> 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" - } - - object ConstantType extends ConstantTypeExtractor { - def apply(value: Constant): ConstantType = { - class UniqueConstantType 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 - } - unique(new UniqueConstantType) - } - } - - private var volatileRecursions: Int = 0 - private val pendingVolatiles = new mutable.HashSet[Symbol] - - /** A class for named types of the form - * `<prefix>.<sym.name>[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 val parentsCache = new ListOfTypesCache { - @inline final def calculate() = thisInfo.parents map transform - } - private var baseTypeSeqCache: BaseTypeSeq = _ - private var baseTypeSeqPeriod = NoPeriod - - 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 = - if (sym.isAliasType) normalize - else if (sym.isNonClassType) transformInfo(sym.info) - else sym.info - - def relativeInfo = if (sym.isNonClassType) transformInfo(pre.memberInfo(sym)) else pre.memberInfo(sym) - - 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] = parentsCache.get() - 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 - - // @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 = typeParamsDirect map (_.typeConstructor) //@M must be .typeConstructor - - // (!result.isEmpty) IFF isHigherKinded - override def typeParams: List[Symbol] = if (isHigherKinded) typeParamsDirect else List() - - override def typeConstructor = TypeRef(pre, sym, Nil) - // note: does not go through typeRef. There's no need to because neither `pre' nor `sym' changes. - // And there's a performance advantage to call TypeRef directly. - - - // a reference (in a Scala program) to a type that has type parameters, but where the reference does not include type arguments - // note that it doesn't matter whether the symbol refers to a java or scala symbol, - // it does matter whether it occurs in java or scala code - // typerefs w/o type params that occur in java signatures/code are considered raw types, and are represented as existential types - 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)) - typeRef(pre, sym, actuals) - else if (sameLength(formals, actuals)) // partial application (needed in infer when bunching type arguments from classes and methods together) - typeRef(pre, sym, dummyArgs).subst(formals, actuals) - else ErrorType - } - else - super.instantiateTypeParams(formals, actuals) - - - private var normalized: Type = null - - @inline private def betaReduce: Type = { - assert(sameLength(sym.info.typeParams, typeArgs), this) - // isHKSubType0 introduces synthetic type params so that betaReduce can first apply sym.info to typeArgs before calling asSeenFrom - // asSeenFrom then skips synthetic type params, which are used to reduce HO subtyping to first-order subtyping, but which can't be instantiated from the given prefix and class - // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) // this crashes pos/depmet_implicit_tpbetareduce.scala - transform(sym.info.resultType) - } - - // @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, typeRef(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 - - 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)) - return normalize.typeArgs.init.mkString("(", ", ", ")") + " => " + normalize.typeArgs.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" - } - - object TypeRef extends TypeRefExtractor { - def apply(pre: Type, sym: Symbol, args: List[Type]): Type = { - unique(new TypeRef(pre, sym, args) with UniqueType) - } - } - - /** 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()) - def apply(tparam: Symbol) = new TypeVar(tparam.tpeHK, new TypeConstraint, List(), tparam.typeParams) // TODO why not initialise TypeConstraint with bounds of tparam? - 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[TypeVar] 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) && { - unifySimple || unifyFull(tp) || unifyFull(tp.dealias) || unifyFull(tp.widen) || 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</code>; - * 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) - // why not do the hash-consing in the SingleType.apply() - // factory, like the other UniqueTypes? - unique(new SingleType(pre1, sym1) with UniqueType) - } - } - - /** 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) - } - } - } - - /** 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), _) => typeRef(pre, sym, Nil) //@M drop type args to Any/Nothing - case TypeRef(pre, sym, _) => typeRef(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 typeRef(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]() - 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(_, _) => // stop to avoid infinite expansions - tp - 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 = from.toSet // avoiding repeatedly traversing from - 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 - - 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) - - 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 { - 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) => typeRef(pre, sym, args) - case SingleType(pre, _) => singleType(pre, sym) - } - override def apply(tp: Type): Type = if (from.isEmpty) tp else { - 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(typeRef(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 typeRef(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+" <:<? "+tp2 - } - -// Helper Methods ------------------------------------------------------------- - - final val LubGlbMargin = 0 - - /** The maximum allowable depth of lubs or glbs over types `ts' - * This is the maximum depth of all types in the base type sequences - * of each of the types `ts', plus LubGlbMargin - */ - def lubDepth(ts: List[Type]) = { - var d = 0 - for (tp <- ts) d = math.max(d, tp.baseTypeSeqDepth) - d + LubGlbMargin - } - - /** Is intersection of given types populated? That is, - * for all types tp1, tp2 in intersection - * for all common base classes bc of tp1 and tp2 - * let bt1, bt2 be the base types of tp1, tp2 relative to class bc - * Then: - * bt1 and bt2 have the same prefix, and - * any corresponding non-variant type arguments of bt1 and bt2 are the same - */ - def isPopulated(tp1: Type, tp2: Type): Boolean = { - def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { - case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => - assert(sym1 == sym2) - pre1 =:= pre2 && - ((args1, args2, sym1.typeParams).zipped forall { - (arg1, arg2, tparam) => - //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG - if (tparam.variance == 0) arg1 =:= arg2 - else if (arg1.isInstanceOf[TypeVar]) - // if left-hand argument is a typevar, make it compatible with variance - // this is for more precise pattern matching - // todo: work this in the spec of this method - // also: think what happens if there are embedded typevars? - if (tparam.variance < 0) arg1 <:< arg2 else arg2 <:< arg1 - else true - }) - case (et: ExistentialType, _) => - et.withTypeVars(isConsistent(_, tp2)) - case (_, et: ExistentialType) => - et.withTypeVars(isConsistent(tp1, _)) - } - - def check(tp1: Type, tp2: Type) = - if (tp1.typeSymbol.isClass && tp1.typeSymbol.hasFlag(FINAL)) - tp1 <:< tp2 || isNumericValueClass(tp1.typeSymbol) && isNumericValueClass(tp2.typeSymbol) - else tp1.baseClasses forall (bc => - tp2.baseTypeIndex(bc) < 0 || isConsistent(tp1.baseType(bc), tp2.baseType(bc))) - - check(tp1, tp2)/* && check(tp2, tp1)*/ // need to investgate why this can't be made symmetric -- neg/gadts1 fails, and run/existials also. - } - - /** Does a pattern of type `patType' need an outer test when executed against - * selector type `selType' in context defined by `currentOwner'? - */ - def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = { - def createDummyClone(pre: Type): Type = { - val dummy = currentOwner.enclClass.newValue(NoPosition, nme.ANYNAME).setInfo(pre.widen) - singleType(ThisType(currentOwner.enclClass), dummy) - } - def maybeCreateDummyClone(pre: Type, sym: Symbol): Type = pre match { - case SingleType(pre1, sym1) => - if (sym1.isModule && sym1.isStatic) { - NoType - } else if (sym1.isModule && sym.owner == sym1.moduleClass) { - val pre2 = maybeCreateDummyClone(pre1, sym1) - if (pre2 eq NoType) pre2 - else singleType(pre2, sym1) - } else { - createDummyClone(pre) - } - case ThisType(clazz) => - if (clazz.isModuleClass) - maybeCreateDummyClone(clazz.typeOfThis, sym) - else if (sym.owner == clazz && (sym.hasFlag(PRIVATE) || sym.privateWithin == clazz)) - NoType - else - createDummyClone(pre) - case _ => - NoType - } - patType match { - case TypeRef(pre, sym, args) => - val pre1 = maybeCreateDummyClone(pre, sym) - (pre1 ne NoType) && isPopulated(typeRef(pre1, sym, args), selType) - case _ => - false - } - } - - private var subsametypeRecursions: Int = 0 - - private def isUnifiable(pre1: Type, pre2: Type) = - (beginsWithTypeVarOrIsRefined(pre1) || beginsWithTypeVarOrIsRefined(pre2)) && (pre1 =:= pre2) - - /** Returns true iff we are past phase specialize, - * sym1 and sym2 are two existential skolems with equal names and bounds, - * and pre1 and pre2 are equal prefixes - */ - private def isSameSpecializedSkolem(sym1: Symbol, sym2: Symbol, pre1: Type, pre2: Type) = { - sym1.isExistentialSkolem && sym2.isExistentialSkolem && - sym1.name == sym2.name && - phase.specialized && - sym1.info =:= sym2.info && - pre1 =:= pre2 - } - - private def equalSymsAndPrefixes(sym1: Symbol, pre1: Type, sym2: Symbol, pre2: Type): Boolean = - if (sym1 == sym2) sym1.hasPackageFlag || phase.erasedTypes || pre1 =:= pre2 - else (sym1.name == sym2.name) && isUnifiable(pre1, pre2) - - /** Do `tp1' and `tp2' denote equivalent types? - */ - def isSameType(tp1: Type, tp2: Type): Boolean = try { - incCounter(sametypeCount) - subsametypeRecursions += 1 - undoLog undoUnless { - isSameType1(tp1, tp2) - } - } finally { - subsametypeRecursions -= 1 - // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866) - // it doesn't help to keep separate recursion counts for the three methods that now share it - // if (subsametypeRecursions == 0) undoLog.clear() - } - - def isDifferentType(tp1: Type, tp2: Type): Boolean = try { - subsametypeRecursions += 1 - undoLog undo { // undo type constraints that arise from operations in this block - !isSameType1(tp1, tp2) - } - } finally { - subsametypeRecursions -= 1 - // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866) - // it doesn't help to keep separate recursion counts for the three methods that now share it - // if (subsametypeRecursions == 0) undoLog.clear() - } - - def isDifferentTypeConstructor(tp1: Type, tp2: Type): Boolean = tp1 match { - case TypeRef(pre1, sym1, _) => - tp2 match { - case TypeRef(pre2, sym2, _) => sym1 != sym2 || isDifferentType(pre1, pre2) - case _ => true - } - case _ => true - } - - def normalizePlus(tp: Type) = - if (isRawType(tp)) rawToExistential(tp) - else tp.normalize - - /* - todo: change to: - def normalizePlus(tp: Type) = tp match { - case TypeRef(pre, sym, List()) => - if (!sym.isInitialized) sym.rawInfo.load(sym) - if (sym.isJavaDefined && !sym.typeParams.isEmpty) rawToExistential(tp) - else tp.normalize - case _ => tp.normalize - } - */ -/* - private def isSameType0(tp1: Type, tp2: Type): Boolean = { - if (tp1 eq tp2) return true - ((tp1, tp2) match { - case (ErrorType, _) => true - case (WildcardType, _) => true - case (_, ErrorType) => true - case (_, WildcardType) => true - - case (NoType, _) => false - case (NoPrefix, _) => tp2.typeSymbol.isPackageClass - case (_, NoType) => false - case (_, NoPrefix) => tp1.typeSymbol.isPackageClass - - case (ThisType(sym1), ThisType(sym2)) - if (sym1 == sym2) => - true - case (SingleType(pre1, sym1), SingleType(pre2, sym2)) - if (equalSymsAndPrefixes(sym1, pre1, sym2, pre2)) => - true -/* - case (SingleType(pre1, sym1), ThisType(sym2)) - if (sym1.isModule && - sym1.moduleClass == sym2 && - pre1 =:= sym2.owner.thisType) => - true - case (ThisType(sym1), SingleType(pre2, sym2)) - if (sym2.isModule && - sym2.moduleClass == sym1 && - pre2 =:= sym1.owner.thisType) => - true -*/ - case (ConstantType(value1), ConstantType(value2)) => - value1 == value2 - case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => - equalSymsAndPrefixes(sym1, pre1, sym2, pre2) && - ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) || - isSameTypes(args1, args2)) - // @M! normalize reduces higher-kinded case to PolyType's - case (RefinedType(parents1, ref1), RefinedType(parents2, ref2)) => - def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall { - sym2 => - var e1 = s1.lookupEntry(sym2.name) - (e1 ne null) && { - val substSym = sym2.info.substThis(sym2.owner, e1.sym.owner.thisType) - var isEqual = false - while (!isEqual && (e1 ne null)) { - isEqual = e1.sym.info =:= substSym - e1 = s1.lookupNextEntry(e1) - } - isEqual - } - } - //Console.println("is same? " + tp1 + " " + tp2 + " " + tp1.typeSymbol.owner + " " + tp2.typeSymbol.owner)//DEBUG - isSameTypes(parents1, parents2) && isSubScope(ref1, ref2) && isSubScope(ref2, ref1) - case (MethodType(params1, res1), MethodType(params2, res2)) => - // new dependent types: probably fix this, use substSym as done for PolyType - (isSameTypes(tp1.paramTypes, tp2.paramTypes) && - res1 =:= res2 && - tp1.isImplicit == tp2.isImplicit) - case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => - // assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length))) - (tparams1.length == tparams2.length) && (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && // @M looks like it might suffer from same problem as #2210 - res1 =:= res2.substSym(tparams2, tparams1) - case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) => - (tparams1.length == tparams2.length) && (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && // @M looks like it might suffer from same problem as #2210 - res1 =:= res2.substSym(tparams2, tparams1) - case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => - lo1 =:= lo2 && hi1 =:= hi2 - case (BoundedWildcardType(bounds), _) => - bounds containsType tp2 - case (_, BoundedWildcardType(bounds)) => - bounds containsType tp1 - case (tv @ TypeVar(_,_), tp) => - tv.registerTypeEquality(tp, true) - case (tp, tv @ TypeVar(_,_)) => - tv.registerTypeEquality(tp, false) - case (AnnotatedType(_,_,_), _) => - annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations - case (_, AnnotatedType(_,_,_)) => - annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations - case (_: SingletonType, _: SingletonType) => - var origin1 = tp1 - while (origin1.underlying.isInstanceOf[SingletonType]) { - assert(origin1 ne origin1.underlying, origin1) - origin1 = origin1.underlying - } - var origin2 = tp2 - while (origin2.underlying.isInstanceOf[SingletonType]) { - assert(origin2 ne origin2.underlying, origin2) - origin2 = origin2.underlying - } - ((origin1 ne tp1) || (origin2 ne tp2)) && (origin1 =:= origin2) - case _ => - false - }) || { - val tp1n = normalizePlus(tp1) - val tp2n = normalizePlus(tp2) - ((tp1n ne tp1) || (tp2n ne tp2)) && isSameType(tp1n, tp2n) - } - } -*/ - private def isSameType1(tp1: Type, tp2: Type): Boolean = { - if ((tp1 eq tp2) || - (tp1 eq ErrorType) || (tp1 eq WildcardType) || - (tp2 eq ErrorType) || (tp2 eq WildcardType)) - true - else if ((tp1 eq NoType) || (tp2 eq NoType)) - false - else if (tp1 eq NoPrefix) - tp2.typeSymbol.isPackageClass - else if (tp2 eq NoPrefix) - tp1.typeSymbol.isPackageClass - else { - isSameType2(tp1, tp2) || { - val tp1n = normalizePlus(tp1) - val tp2n = normalizePlus(tp2) - ((tp1n ne tp1) || (tp2n ne tp2)) && isSameType(tp1n, tp2n) - } - } - } - - def isSameType2(tp1: Type, tp2: Type): Boolean = { - tp1 match { - case tr1: TypeRef => - tp2 match { - case tr2: TypeRef => - return (equalSymsAndPrefixes(tr1.sym, tr1.pre, tr2.sym, tr2.pre) && - ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) || - isSameTypes(tr1.args, tr2.args))) || - ((tr1.pre, tr2.pre) match { - case (tv @ TypeVar(_,_), _) => tv.registerTypeSelection(tr1.sym, tr2) - case (_, tv @ TypeVar(_,_)) => tv.registerTypeSelection(tr2.sym, tr1) - case _ => false - }) - case _ => - } - case tt1: ThisType => - tp2 match { - case tt2: ThisType => - if (tt1.sym == tt2.sym) return true - case _ => - } - case st1: SingleType => - tp2 match { - case st2: SingleType => - if (equalSymsAndPrefixes(st1.sym, st1.pre, st2.sym, st2.pre)) return true - case _ => - } - case ct1: ConstantType => - tp2 match { - case ct2: ConstantType => - return (ct1.value == ct2.value) - case _ => - } - case rt1: RefinedType => - tp2 match { - case rt2: RefinedType => // - def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall { - sym2 => - var e1 = s1.lookupEntry(sym2.name) - (e1 ne null) && { - val substSym = sym2.info.substThis(sym2.owner, e1.sym.owner.thisType) - var isEqual = false - while (!isEqual && (e1 ne null)) { - isEqual = e1.sym.info =:= substSym - e1 = s1.lookupNextEntry(e1) - } - isEqual - } - } - //Console.println("is same? " + tp1 + " " + tp2 + " " + tp1.typeSymbol.owner + " " + tp2.typeSymbol.owner)//DEBUG - return isSameTypes(rt1.parents, rt2.parents) && { - val decls1 = rt1.decls - val decls2 = rt2.decls - isSubScope(decls1, decls2) && isSubScope(decls2, decls1) - } - case _ => - } - case mt1: MethodType => - tp2 match { - case mt2: MethodType => - // DEPMETTODO new dependent types: probably fix this, use substSym as done for PolyType - return isSameTypes(mt1.paramTypes, mt2.paramTypes) && - mt1.resultType =:= mt2.resultType && - mt1.isImplicit == mt2.isImplicit - // note: no case NullaryMethodType(restpe) => return mt1.params.isEmpty && mt1.resultType =:= restpe - case _ => - } - case NullaryMethodType(restpe1) => - tp2 match { - // note: no case mt2: MethodType => return mt2.params.isEmpty && restpe =:= mt2.resultType - case NullaryMethodType(restpe2) => - return restpe1 =:= restpe2 - case _ => - } - case PolyType(tparams1, res1) => - tp2 match { - case PolyType(tparams2, res2) => -// assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length))) - // @M looks like it might suffer from same problem as #2210 - return ( - (sameLength(tparams1, tparams2)) && // corresponds does not check length of two sequences before checking the predicate - (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && - res1 =:= res2.substSym(tparams2, tparams1) - ) - case _ => - } - case ExistentialType(tparams1, res1) => - tp2 match { - case ExistentialType(tparams2, res2) => - // @M looks like it might suffer from same problem as #2210 - return ( - // corresponds does not check length of two sequences before checking the predicate -- faster & needed to avoid crasher in #2956 - sameLength(tparams1, tparams2) && - (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && - res1 =:= res2.substSym(tparams2, tparams1) - ) - case _ => - } - case TypeBounds(lo1, hi1) => - tp2 match { - case TypeBounds(lo2, hi2) => - return lo1 =:= lo2 && hi1 =:= hi2 - case _ => - } - case BoundedWildcardType(bounds) => - return bounds containsType tp2 - case _ => - } - tp2 match { - case BoundedWildcardType(bounds) => - return bounds containsType tp1 - case _ => - } - tp1 match { - case tv @ TypeVar(_,_) => - return tv.registerTypeEquality(tp2, true) - case _ => - } - tp2 match { - case tv @ TypeVar(_,_) => - return tv.registerTypeEquality(tp1, false) - case _ => - } - tp1 match { - case _: AnnotatedType => - return annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations - case _ => - } - tp2 match { - case _: AnnotatedType => - return annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations - case _ => - } - tp1 match { - case _: SingletonType => - tp2 match { - case _: SingletonType => - @inline def chaseDealiasedUnderlying(tp: Type): Type = { - var origin = tp - var next = origin.underlying.dealias - while (next.isInstanceOf[SingletonType]) { - assert(origin ne next, origin) - origin = next - next = origin.underlying.dealias - } - origin - } - val origin1 = chaseDealiasedUnderlying(tp1) - val origin2 = chaseDealiasedUnderlying(tp2) - ((origin1 ne tp1) || (origin2 ne tp2)) && (origin1 =:= origin2) - case _ => - false - } - case _ => - false - } - } - - /** Are `tps1' and `tps2' lists of pairwise equivalent - * types? - */ - def isSameTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1 corresponds tps2)(_ =:= _) - - /** True if two lists have the same length. Since calling length on linear sequences - * is O(n), it is an inadvisable way to test length equality. - */ - final def sameLength(xs1: List[_], xs2: List[_]) = compareLengths(xs1, xs2) == 0 - @tailrec final def compareLengths(xs1: List[_], xs2: List[_]): Int = - if (xs1.isEmpty) { if (xs2.isEmpty) 0 else -1 } - else if (xs2.isEmpty) 1 - else compareLengths(xs1.tail, xs2.tail) - - /** Again avoiding calling length, but the lengthCompare interface is clunky. - */ - final def hasLength(xs: List[_], len: Int) = xs.lengthCompare(len) == 0 - - private val pendingSubTypes = new mutable.HashSet[SubTypePair] - private var basetypeRecursions: Int = 0 - private val pendingBaseTypes = new mutable.HashSet[Type] - - def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, AnyDepth) - - def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean = try { - subsametypeRecursions += 1 - - undoLog undoUnless { // if subtype test fails, it should not affect constraints on typevars - if (subsametypeRecursions >= LogPendingSubTypesThreshold) { - val p = new SubTypePair(tp1, tp2) - if (pendingSubTypes(p)) - false - else - try { - pendingSubTypes += p - isSubType2(tp1, tp2, depth) - } finally { - pendingSubTypes -= p - } - } else { - isSubType2(tp1, tp2, depth) - } - } - } finally { - subsametypeRecursions -= 1 - // XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866) - // it doesn't help to keep separate recursion counts for the three methods that now share it - // if (subsametypeRecursions == 0) undoLog.clear() - } - - /** Does this type have a prefix that begins with a type variable, - * or is it a refinement type? For type prefixes that fulfil this condition, - * type selections with the same name of equal (wrt) =:= prefixes are - * considered equal wrt =:= - */ - def beginsWithTypeVarOrIsRefined(tp: Type): Boolean = tp match { - case SingleType(pre, sym) => - !(sym hasFlag PACKAGE) && beginsWithTypeVarOrIsRefined(pre) - case tv@TypeVar(_, constr) => - !tv.instValid || beginsWithTypeVarOrIsRefined(constr.inst) - case RefinedType(_, _) => - true - case _ => - false - } - - def instTypeVar(tp: Type): Type = tp match { - case TypeRef(pre, sym, args) => - typeRef(instTypeVar(pre), sym, args) - case SingleType(pre, sym) => - singleType(instTypeVar(pre), sym) - case TypeVar(_, constr) => - instTypeVar(constr.inst) - case _ => - tp - } - - def isErrorOrWildcard(tp: Type) = (tp eq ErrorType) || (tp eq WildcardType) - - def isSingleType(tp: Type) = tp match { - case ThisType(_) | SuperType(_, _) | SingleType(_, _) => true - case _ => false - } - - def isConstantType(tp: Type) = tp match { - case ConstantType(_) => true - case _ => false - } - - // @assume tp1.isHigherKinded || tp2.isHigherKinded - def isHKSubType0(tp1: Type, tp2: Type, depth: Int): Boolean = ( - tp1.typeSymbol == NothingClass - || - tp2.typeSymbol == AnyClass // @M Any and Nothing are super-type resp. subtype of every well-kinded type - || // @M! normalize reduces higher-kinded case to PolyType's - ((tp1.normalize.withoutAnnotations , tp2.normalize.withoutAnnotations) match { - case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => // @assume tp1.isHigherKinded && tp2.isHigherKinded (as they were both normalized to PolyType) - sameLength(tparams1, tparams2) && { - if (tparams1.head.owner.isMethod) { // fast-path: polymorphic method type -- type params cannot be captured - (tparams1 corresponds tparams2)((p1, p2) => p2.info.substSym(tparams2, tparams1) <:< p1.info) && - res1 <:< res2.substSym(tparams2, tparams1) - } else { // normalized higher-kinded type - //@M for an example of why we need to generate fresh symbols, see neg/tcpoly_ticket2101.scala - val tpsFresh = cloneSymbols(tparams1) - - (tparams1 corresponds tparams2)((p1, p2) => - p2.info.substSym(tparams2, tpsFresh) <:< p1.info.substSym(tparams1, tpsFresh)) && - res1.substSym(tparams1, tpsFresh) <:< res2.substSym(tparams2, tpsFresh) - - //@M the forall in the previous test could be optimised to the following, - // but not worth the extra complexity since it only shaves 1s from quick.comp - // (List.forall2(tpsFresh/*optimisation*/, tparams2)((p1, p2) => - // p2.info.substSym(tparams2, tpsFresh) <:< p1.info /*optimisation, == (p1 from tparams1).info.substSym(tparams1, tpsFresh)*/) && - // this optimisation holds because inlining cloneSymbols in `val tpsFresh = cloneSymbols(tparams1)` gives: - // val tpsFresh = tparams1 map (_.cloneSymbol) - // for (tpFresh <- tpsFresh) tpFresh.setInfo(tpFresh.info.substSym(tparams1, tpsFresh)) - } - } && annotationsConform(tp1.normalize, tp2.normalize) - case (_, _) => false // @assume !tp1.isHigherKinded || !tp2.isHigherKinded - // --> thus, cannot be subtypes (Any/Nothing has already been checked) - })) - - /** True if all three arguments have the same number of elements and - * the function is true for all the triples. - */ - @tailrec final def corresponds3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C], f: (A, B, C) => Boolean): Boolean = { - if (xs1.isEmpty) xs2.isEmpty && xs3.isEmpty - else !xs2.isEmpty && !xs3.isEmpty && f(xs1.head, xs2.head, xs3.head) && corresponds3(xs1.tail, xs2.tail, xs3.tail, f) - } - - def isSubArg(t1: Type, t2: Type, variance: Int) = - (variance > 0 || t2 <:< t1) && (variance < 0 || t1 <:< t2) - - def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean = - corresponds3(tps1, tps2, tparams map (_.variance), isSubArg) - - def differentOrNone(tp1: Type, tp2: Type) = if (tp1 eq tp2) NoType else tp1 - - /** Does type `tp1' conform to `tp2'? - */ - private def isSubType2(tp1: Type, tp2: Type, depth: Int): Boolean = { - if ((tp1 eq tp2) || isErrorOrWildcard(tp1) || isErrorOrWildcard(tp2)) return true - if ((tp1 eq NoType) || (tp2 eq NoType)) return false - if (tp1 eq NoPrefix) return (tp2 eq NoPrefix) || tp2.typeSymbol.isPackageClass - if (tp2 eq NoPrefix) return tp1.typeSymbol.isPackageClass - if (isSingleType(tp1) && isSingleType(tp2) || isConstantType(tp1) && isConstantType(tp2)) return tp1 =:= tp2 - if (tp1.isHigherKinded || tp2.isHigherKinded) return isHKSubType0(tp1, tp2, depth) - - /** First try, on the right: - * - unwrap Annotated types, BoundedWildcardTypes, - * - bind TypeVars on the right, if lhs is not Annotated nor BoundedWildcard - * - handle common cases for first-kind TypeRefs on both sides as a fast path. - */ - def firstTry = { incCounter(ctr1); tp2 match { - // fast path: two typerefs, none of them HK - case tr2: TypeRef => - tp1 match { - case tr1: TypeRef => - val sym1 = tr1.sym - val sym2 = tr2.sym - val pre1 = tr1.pre - val pre2 = tr2.pre - (((if (sym1 == sym2) phase.erasedTypes || pre1 <:< pre2 - else (sym1.name == sym2.name && !sym1.isModuleClass && !sym2.isModuleClass && - (isUnifiable(pre1, pre2) || isSameSpecializedSkolem(sym1, sym2, pre1, pre2)))) && - isSubArgs(tr1.args, tr2.args, sym1.typeParams)) - || - sym2.isClass && { - val base = tr1 baseType sym2 - (base ne tr1) && base <:< tr2 - } - || - thirdTryRef(tr1, tr2)) - case _ => - secondTry - } - case AnnotatedType(_, _, _) => - tp1.withoutAnnotations <:< tp2.withoutAnnotations && annotationsConform(tp1, tp2) - case BoundedWildcardType(bounds) => - tp1 <:< bounds.hi - case tv2 @ TypeVar(_, constr2) => - tp1 match { - case AnnotatedType(_, _, _) | BoundedWildcardType(_) => - secondTry - case _ => - tv2.registerBound(tp1, true) - } - case _ => - secondTry - }} - - /** Second try, on the left: - * - unwrap AnnotatedTypes, BoundedWildcardTypes, - * - bind typevars, - * - handle existential types by skolemization. - */ - def secondTry = { incCounter(ctr2); tp1 match { - case AnnotatedType(_, _, _) => - tp1.withoutAnnotations <:< tp2.withoutAnnotations && annotationsConform(tp1, tp2) - case BoundedWildcardType(bounds) => - tp1.bounds.lo <:< tp2 - case tv @ TypeVar(_,_) => - tv.registerBound(tp2, false) - case ExistentialType(_, _) => - try { - skolemizationLevel += 1 - tp1.skolemizeExistential <:< tp2 - } finally { - skolemizationLevel -= 1 - } - case _ => - thirdTry - }} - - def thirdTryRef(tp1: Type, tp2: TypeRef): Boolean = { - incCounter(ctr3); - val sym2 = tp2.sym - sym2 match { - case NotNullClass => tp1.isNotNull - case SingletonClass => tp1.isStable || fourthTry - case _: ClassSymbol => - if (isRaw(sym2, tp2.args)) - isSubType(tp1, rawToExistential(tp2), depth) - else if (sym2.name == tpnme.REFINE_CLASS_NAME) - isSubType(tp1, sym2.info, depth) - else - fourthTry - case _: TypeSymbol => - if (sym2 hasFlag DEFERRED) { - val tp2a = tp2.bounds.lo - isDifferentTypeConstructor(tp2, tp2a) && tp1 <:< tp2a || fourthTry - } else { - isSubType(tp1.normalize, tp2.normalize, depth) - } - case _ => - fourthTry - } - } - - /** Third try, on the right: - * - decompose refined types. - * - handle typerefs, existentials, and notnull types. - * - handle left+right method types, polytypes, typebounds - */ - def thirdTry = { incCounter(ctr3); tp2 match { - case tr2: TypeRef => - thirdTryRef(tp1, tr2) - case rt2: RefinedType => - (rt2.parents forall (tp1 <:< _)) && - (rt2.decls.toList forall tp1.specializes) - case et2: ExistentialType => - et2.withTypeVars(tp1 <:< _, depth) || fourthTry - case nn2: NotNullType => - tp1.isNotNull && tp1 <:< nn2.underlying - case mt2: MethodType => - tp1 match { - case mt1 @ MethodType(params1, res1) => - val params2 = mt2.params - val res2 = mt2.resultType - (sameLength(params1, params2) && - matchingParams(params1, params2, mt1.isJava, mt2.isJava) && - (res1 <:< res2) && - mt1.isImplicit == mt2.isImplicit) - // TODO: if mt1.params.isEmpty, consider NullaryMethodType? - case _ => - false - } - case pt2 @ NullaryMethodType(_) => - tp1 match { - // TODO: consider MethodType mt for which mt.params.isEmpty?? - case pt1 @ NullaryMethodType(_) => - pt1.resultType <:< pt2.resultType - case _ => - false - } - case TypeBounds(lo2, hi2) => - tp1 match { - case TypeBounds(lo1, hi1) => - lo2 <:< lo1 && hi1 <:< hi2 - case _ => - false - } - case _ => - fourthTry - }} - - /** Fourth try, on the left: - * - handle typerefs, refined types, notnull and singleton types. - */ - def fourthTry = { incCounter(ctr4); tp1 match { - case tr1 @ TypeRef(_, sym1, _) => - sym1 match { - case NothingClass => true - case NullClass => - tp2 match { - case TypeRef(_, sym2, _) => - sym2.isClass && (sym2 isNonBottomSubClass ObjectClass) && - !(tp2.normalize.typeSymbol isNonBottomSubClass NotNullClass) - case _ => - isSingleType(tp2) && tp1 <:< tp2.widen - } - case _: ClassSymbol => - if (isRaw(sym1, tr1.args)) - isSubType(rawToExistential(tp1), tp2, depth) - else - sym1.name == tpnme.REFINE_CLASS_NAME && - isSubType(sym1.info, tp2, depth) - case _: TypeSymbol => - if (sym1 hasFlag DEFERRED) { - val tp1a = tp1.bounds.hi - isDifferentTypeConstructor(tp1, tp1a) && tp1a <:< tp2 - } else { - isSubType(tp1.normalize, tp2.normalize, depth) - } - case _ => - false - } - case RefinedType(parents1, _) => - parents1 exists (_ <:< tp2) - case _: SingletonType | _: NotNullType => - tp1.underlying <:< tp2 - case _ => - false - }} - - firstTry - } - - /** Are `tps1' and `tps2' lists of equal length such - * that all elements of `tps1' conform to corresponding elements - * of `tps2'? - */ - def isSubTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1 corresponds tps2)(_ <:< _) - - /** Does type `tp' implement symbol `sym' with same or - * stronger type? Exact only if `sym' is a member of some - * refinement type, otherwise we might return false negatives. - */ - def specializesSym(tp: Type, sym: Symbol): Boolean = - tp.typeSymbol == NothingClass || - tp.typeSymbol == NullClass && (sym.owner isSubClass ObjectClass) || - (tp.nonPrivateMember(sym.name).alternatives exists - (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym))) - - /** Does member `sym1' of `tp1' have a stronger type - * than member `sym2' of `tp2'? - */ - private def specializesSym(tp1: Type, sym1: Symbol, tp2: Type, sym2: Symbol): Boolean = { - val info1 = tp1.memberInfo(sym1) - val info2 = tp2.memberInfo(sym2).substThis(tp2.typeSymbol, tp1) - //System.out.println("specializes "+tp1+"."+sym1+":"+info1+sym1.locationString+" AND "+tp2+"."+sym2+":"+info2)//DEBUG - sym2.isTerm && (info1 <:< info2) /*&& (!sym2.isStable || sym1.isStable) */ || - sym2.isAbstractType && { - val memberTp1 = tp1.memberType(sym1) - // println("kinds conform? "+(memberTp1, tp1, sym2, kindsConform(List(sym2), List(memberTp1), tp2, sym2.owner))) - info2.bounds.containsType(memberTp1) && - kindsConform(List(sym2), List(memberTp1), tp1, sym1.owner) - } || - sym2.isAliasType && tp2.memberType(sym2).substThis(tp2.typeSymbol, tp1) =:= tp1.memberType(sym1) //@MAT ok - } - - /** A function implementing `tp1' matches `tp2' */ - final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = { - def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean = ( - sameLength(tparams1, tparams2) && - matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple) - ) - def lastTry = - tp2 match { - case ExistentialType(_, res2) if alwaysMatchSimple => - matchesType(tp1, res2, true) - case MethodType(_, _) => - false - case PolyType(tparams2, res2) => - tparams2.isEmpty && matchesType(tp1, res2, alwaysMatchSimple) - case _ => - alwaysMatchSimple || tp1 =:= tp2 - } - tp1 match { - case mt1 @ MethodType(params1, res1) => - tp2 match { - case mt2 @ MethodType(params2, res2) => - sameLength(params1, params2) && // useful pre-screening optimization - matchingParams(params1, params2, mt1.isJava, mt2.isJava) && - matchesType(res1, res2, alwaysMatchSimple) && - mt1.isImplicit == mt2.isImplicit - case NullaryMethodType(res2) => - if (params1.isEmpty) matchesType(res1, res2, alwaysMatchSimple) - else matchesType(tp1, res2, alwaysMatchSimple) - case ExistentialType(_, res2) => - alwaysMatchSimple && matchesType(tp1, res2, true) - case _ => - false - } - case mt1 @ NullaryMethodType(res1) => - tp2 match { - case mt2 @ MethodType(Nil, res2) => // could never match if params nonEmpty, and !mt2.isImplicit is implied by empty param list - matchesType(res1, res2, alwaysMatchSimple) - case NullaryMethodType(res2) => - matchesType(res1, res2, alwaysMatchSimple) - case ExistentialType(_, res2) => - alwaysMatchSimple && matchesType(tp1, res2, true) - case _ => - matchesType(res1, tp2, alwaysMatchSimple) - } - case PolyType(tparams1, res1) => - tp2 match { - case PolyType(tparams2, res2) => - matchesQuantified(tparams1, tparams2, res1, res2) - case ExistentialType(_, res2) => - alwaysMatchSimple && matchesType(tp1, res2, true) - case _ => - false // remember that tparams1.nonEmpty is now an invariant of PolyType - } - case ExistentialType(tparams1, res1) => - tp2 match { - case ExistentialType(tparams2, res2) => - matchesQuantified(tparams1, tparams2, res1, res2) - case _ => - if (alwaysMatchSimple) matchesType(res1, tp2, true) - else lastTry - } - case _ => - lastTry - } - } - -/** matchesType above is an optimized version of the following implementation: - - def matchesType2(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = { - def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean = - tparams1.length == tparams2.length && - matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple) - (tp1, tp2) match { - case (MethodType(params1, res1), MethodType(params2, res2)) => - params1.length == params2.length && // useful pre-secreening optimization - matchingParams(params1, params2, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && - matchesType(res1, res2, alwaysMatchSimple) && - tp1.isImplicit == tp2.isImplicit - case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => - matchesQuantified(tparams1, tparams2, res1, res2) - case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) => - matchesType(rtp1, rtp2, alwaysMatchSimple) - case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) => - matchesType(rtp1, rtp2, alwaysMatchSimple) - case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) => - matchesQuantified(tparams1, tparams2, res1, res2) - case (ExistentialType(_, res1), _) if alwaysMatchSimple => - matchesType(res1, tp2, alwaysMatchSimple) - case (_, ExistentialType(_, res2)) if alwaysMatchSimple => - matchesType(tp1, res2, alwaysMatchSimple) - case (NullaryMethodType(rtp1), _) => - matchesType(rtp1, tp2, alwaysMatchSimple) - case (_, NullaryMethodType(rtp2)) => - matchesType(tp1, rtp2, alwaysMatchSimple) - case (MethodType(_, _), _) => false - case (PolyType(_, _), _) => false - case (_, MethodType(_, _)) => false - case (_, PolyType(_, _)) => false - case _ => - alwaysMatchSimple || tp1 =:= tp2 - } - } -*/ - - /** Are `syms1' and `syms2' parameter lists with pairwise equivalent types? */ - private def matchingParams(syms1: List[Symbol], syms2: List[Symbol], syms1isJava: Boolean, syms2isJava: Boolean): Boolean = syms1 match { - case Nil => - syms2.isEmpty - case sym1 :: rest1 => - syms2 match { - case Nil => - false - case sym2 :: rest2 => - val tp1 = sym1.tpe - val tp2 = sym2.tpe - (tp1 =:= tp2 || - syms1isJava && tp2.typeSymbol == ObjectClass && tp1.typeSymbol == AnyClass || - syms2isJava && tp1.typeSymbol == ObjectClass && tp2.typeSymbol == AnyClass) && - matchingParams(rest1, rest2, syms1isJava, syms2isJava) - } - } - - /** like map2, but returns list `xs' itself - instead of a copy - if function - * `f' maps all elements to themselves. - */ - def map2Conserve[A <: AnyRef, B](xs: List[A], ys: List[B])(f: (A, B) => A): List[A] = - if (xs.isEmpty) xs - else { - val x1 = f(xs.head, ys.head) - val xs1 = map2Conserve(xs.tail, ys.tail)(f) - if ((x1 eq xs.head) && (xs1 eq xs.tail)) xs - else x1 :: xs1 - } - - /** Solve constraint collected in types `tvars'. - * - * @param tvars All type variables to be instantiated. - * @param tparams The type parameters corresponding to `tvars' - * @param variances The variances of type parameters; need to reverse - * solution direction for all contravariant variables. - * @param upper When `true' search for max solution else min. - */ - def solve(tvars: List[TypeVar], tparams: List[Symbol], - variances: List[Int], upper: Boolean): Boolean = - solve(tvars, tparams, variances, upper, AnyDepth) - - def solve(tvars: List[TypeVar], tparams: List[Symbol], - variances: List[Int], upper: Boolean, depth: Int): Boolean = { - val config = tvars zip (tparams zip variances) - - def solveOne(tvar: TypeVar, tparam: Symbol, variance: Int) { - if (tvar.constr.inst == NoType) { - val up = if (variance != CONTRAVARIANT) upper else !upper - tvar.constr.inst = null - val bound: Type = if (up) tparam.info.bounds.hi else tparam.info.bounds.lo - //Console.println("solveOne0(tv, tp, v, b)="+(tvar, tparam, variance, bound)) - var cyclic = bound contains tparam - for ((tvar2, (tparam2, variance2)) <- config) { - if (tparam2 != tparam && - ((bound contains tparam2) || - up && (tparam2.info.bounds.lo =:= tparam.tpe) || - !up && (tparam2.info.bounds.hi =:= tparam.tpe))) { - if (tvar2.constr.inst eq null) cyclic = true - solveOne(tvar2, tparam2, variance2) - } - } - if (!cyclic) { - if (up) { - if (bound.typeSymbol != AnyClass) - tvar addHiBound bound.instantiateTypeParams(tparams, tvars) - for (tparam2 <- tparams) - tparam2.info.bounds.lo.dealias match { - case TypeRef(_, `tparam`, _) => - tvar addHiBound tparam2.tpe.instantiateTypeParams(tparams, tvars) - case _ => - } - } else { - if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam) { - tvar addLoBound bound.instantiateTypeParams(tparams, tvars) - } - for (tparam2 <- tparams) - tparam2.info.bounds.hi.dealias match { - case TypeRef(_, `tparam`, _) => - tvar addLoBound tparam2.tpe.instantiateTypeParams(tparams, tvars) - case _ => - } - } - } - tvar.constr.inst = NoType // necessary because hibounds/lobounds may contain tvar - - //println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))) - - tvar setInst ( - if (up) { - if (depth != AnyDepth) glb(tvar.constr.hiBounds, depth) else glb(tvar.constr.hiBounds) - } else { - if (depth != AnyDepth) lub(tvar.constr.loBounds, depth) else lub(tvar.constr.loBounds) - }) - - //Console.println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))+" = "+tvar.constr.inst)//@MDEBUG - } - } - - // println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info))) - for ((tvar, (tparam, variance)) <- config) - solveOne(tvar, tparam, variance) - - tvars forall (tvar => tvar.constr.isWithinBounds(tvar.constr.inst)) - } - - /** Do type arguments `targs' conform to formal parameters - * `tparams'? - * - * @param tparams ... - * @param targs ... - * @return ... - */ - def isWithinBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): Boolean = { - var bounds = instantiatedBounds(pre, owner, tparams, targs) - if (targs.exists(_.annotations.nonEmpty)) - bounds = adaptBoundsToAnnotations(bounds, tparams, targs) - (bounds corresponds targs)(_ containsType _) - } - - def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = - tparams map (_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds) - -// Lubs and Glbs --------------------------------------------------------- - - /** The least sorted upwards closed upper bound of a non-empty list - * of lists of types relative to the following ordering <= between lists of types: - * - * xs <= ys iff forall y in ys exists x in xs such that x <: y - * - * @See baseTypeSeq for a definition of sorted and upwards closed. - */ - private def lubList(tss: List[List[Type]], depth: Int): List[Type] = - if (tss.tail.isEmpty) tss.head - else if (tss exists (_.isEmpty)) List() - else { - val ts0 = tss map (_.head) - val sym = minSym(ts0) - if (ts0 forall (_.typeSymbol == sym)) - mergePrefixAndArgs(elimSub(ts0, depth), 1, depth).toList ::: lubList(tss map (_.tail), depth) - else - lubList(tss map (ts => if (ts.head.typeSymbol == sym) ts.tail else ts), depth) - } - - private def lubBaseTypeSeq(tss: List[BaseTypeSeq], depth: Int): List[Type] = - lubList(tss map (_.toList), depth) - - /** The minimal symbol (wrt Symbol.isLess) of a list of types */ - private def minSym(tps: List[Type]): Symbol = - (tps.head.typeSymbol /: tps.tail) { - (sym1, tp2) => if (tp2.typeSymbol isLess sym1) tp2.typeSymbol else sym1 - } - - /** A minimal type list which has a given list of types as its base type sequence */ - def spanningTypes(ts: List[Type]): List[Type] = ts match { - case List() => List() - case first :: rest => - first :: spanningTypes( - rest filter (t => !first.typeSymbol.isSubClass(t.typeSymbol))) - } - - /** Eliminate from list of types all elements which are a supertype - * of some other element of the list. */ - private def elimSuper(ts: List[Type]): List[Type] = ts match { - case List() => List() - case t :: ts1 => - val rest = elimSuper(ts1 filter (t1 => !(t <:< t1))) - if (rest exists (t1 => t1 <:< t)) rest else t :: rest - } - - /** A collector that tests for existential types appearing at given variance in a type */ - class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) { - def traverse(tp: Type) = tp match { - case ExistentialType(_, _) if (variance == v) => result = true - case _ => mapOver(tp) - } - def init() = { - variance = 1 - this - } - } - - val containsCovariantExistentialCollector = new ContainsVariantExistentialCollector(1) - val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1) - - /** Eliminate from list of types all elements which are a subtype - * of some other element of the list. */ - private def elimSub(ts: List[Type], depth: Int): List[Type] = { - def elimAnonymousClass(t: Type) = t match { - case TypeRef(pre, clazz, List()) if clazz.isAnonymousClass => - clazz.classBound.asSeenFrom(pre, clazz.owner) - case _ => - t - } - def elimSub0(ts: List[Type]): List[Type] = ts match { - case List() => List() - case t :: ts1 => - val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, decr(depth)))) - if (rest exists (t1 => isSubType(t, t1, decr(depth)))) rest else t :: rest - } - val ts0 = elimSub0(ts) - if (ts0.isEmpty || ts0.tail.isEmpty) ts0 - else { - val ts1 = ts0 mapConserve (t => elimAnonymousClass(t.underlying)) - if (ts1 eq ts0) ts0 - else elimSub(ts1, depth) - } - } - - private def stripExistentialsAndTypeVars(ts: List[Type]): (List[Type], List[Symbol]) = { - val quantified = ts flatMap { - case ExistentialType(qs, _) => qs - case t => List() - } - def stripType(tp: Type) = tp match { - case ExistentialType(_, res) => - res - case TypeVar(_, constr) => - if (constr.instValid) constr.inst - else abort("trying to do lub/glb of typevar "+tp) - case t => t - } - val strippedTypes = ts mapConserve stripType - (strippedTypes, quantified) - } - - def weakLub(ts: List[Type]) = - if (ts.nonEmpty && (ts forall isNumericValueType)) (numericLub(ts), true) - else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty))) - (annotationsLub(lub(ts map (_.withoutAnnotations)), ts), true) - else (lub(ts), false) - - def weakGlb(ts: List[Type]) = { - if (ts.nonEmpty && (ts forall isNumericValueType)) { - val nglb = numericGlb(ts) - if (nglb != NoType) (nglb, true) - else (glb(ts), false) - } else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty))) { - (annotationsGlb(glb(ts map (_.withoutAnnotations)), ts), true) - } else (glb(ts), false) - } - - def numericLub(ts: List[Type]) = - ts reduceLeft ((t1, t2) => - if (isNumericSubType(t1, t2)) t2 - else if (isNumericSubType(t2, t1)) t1 - else IntClass.tpe) - - def numericGlb(ts: List[Type]) = - ts reduceLeft ((t1, t2) => - if (isNumericSubType(t1, t2)) t1 - else if (isNumericSubType(t2, t1)) t2 - else NoType) - - def isWeakSubType(tp1: Type, tp2: Type) = - tp1.deconst.normalize match { - case TypeRef(_, sym1, _) if isNumericValueClass(sym1) => - tp2.deconst.normalize match { - case TypeRef(_, sym2, _) if isNumericValueClass(sym2) => - isNumericSubClass(sym1, sym2) - case tv2 @ TypeVar(_, _) => - tv2.registerBound(tp1, isLowerBound = true, isNumericBound = true) - case _ => - isSubType(tp1, tp2) - } - case tv1 @ TypeVar(_, _) => - tp2.deconst.normalize match { - case TypeRef(_, sym2, _) if isNumericValueClass(sym2) => - tv1.registerBound(tp2, isLowerBound = false, isNumericBound = true) - case _ => - isSubType(tp1, tp2) - } - case _ => - isSubType(tp1, tp2) - } - - def isNumericSubType(tp1: Type, tp2: Type) = - isNumericValueType(tp1) && isNumericValueType(tp2) && - isNumericSubClass(tp1.typeSymbol, tp2.typeSymbol) - - private val lubResults = new mutable.HashMap[(Int, List[Type]), Type] - private val glbResults = new mutable.HashMap[(Int, List[Type]), Type] - - def lub(ts: List[Type]): Type = try { - lub(ts, lubDepth(ts)) - } finally { - lubResults.clear() - glbResults.clear() - } - - /** The least upper bound wrt <:< of a list of types */ - def lub(ts: List[Type], depth: Int): Type = { - def lub0(ts0: List[Type]): Type = elimSub(ts0, depth) match { - case List() => NothingClass.tpe - case List(t) => t - case ts @ PolyType(tparams, _) :: _ => - val tparams1 = (tparams, matchingBounds(ts, tparams).transpose).zipped map - ((tparam, bounds) => tparam.cloneSymbol.setInfo(glb(bounds, depth))) - PolyType(tparams1, lub0(matchingInstTypes(ts, tparams1))) - case ts @ MethodType(params, _) :: rest => - MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe)))) - case ts @ NullaryMethodType(_) :: rest => - NullaryMethodType(lub0(matchingRestypes(ts, Nil))) - case ts @ TypeBounds(_, _) :: rest => - TypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth)) - case ts => - lubResults get (depth, ts) match { - case Some(lubType) => - lubType - case None => - lubResults((depth, ts)) = AnyClass.tpe - val res = if (depth < 0) AnyClass.tpe else lub1(ts) - lubResults((depth, ts)) = res - res - } - } - def lub1(ts0: List[Type]): Type = { - val (ts, tparams) = stripExistentialsAndTypeVars(ts0) - val bts: List[BaseTypeSeq] = ts map (_.baseTypeSeq) - val lubBaseTypes: List[Type] = lubBaseTypeSeq(bts, depth) - val lubParents = spanningTypes(lubBaseTypes) - val lubOwner = commonOwner(ts) - val lubBase = intersectionType(lubParents, lubOwner) - val lubType = - if (phase.erasedTypes || depth == 0) lubBase - else { - val lubRefined = refinedType(lubParents, lubOwner) - val lubThisType = lubRefined.typeSymbol.thisType - val narrowts = ts map (_.narrow) - def lubsym(proto: Symbol): Symbol = { - val prototp = lubThisType.memberInfo(proto) - val syms = narrowts map (t => - t.nonPrivateMember(proto.name).suchThat(sym => - sym.tpe matches prototp.substThis(lubThisType.typeSymbol, t))) - if (syms contains NoSymbol) NoSymbol - else { - val symtypes = - (narrowts, syms).zipped map ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)) - if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class - proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, decr(depth))) - else if (symtypes.tail forall (symtypes.head =:=)) - proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(symtypes.head) - else { - def lubBounds(bnds: List[TypeBounds]): TypeBounds = - TypeBounds(glb(bnds map (_.lo), decr(depth)), lub(bnds map (_.hi), decr(depth))) - lubRefined.typeSymbol.newAbstractType(proto.pos, proto.name.toTypeName) - .setInfoOwnerAdjusted(lubBounds(symtypes map (_.bounds))) - } - } - } - def refines(tp: Type, sym: Symbol): Boolean = { - val syms = tp.nonPrivateMember(sym.name).alternatives; - !syms.isEmpty && (syms forall (alt => - // todo alt != sym is strictly speaking not correct, but without it we lose - // efficiency. - alt != sym && !specializesSym(lubThisType, sym, tp, alt))) - } - for (sym <- lubBase.nonPrivateMembers) { - // add a refinement symbol for all non-class members of lubBase - // which are refined by every type in ts. - if (!sym.isClass && !sym.isConstructor && (narrowts forall (t => refines(t, sym)))) - try { - val lsym = lubsym(sym) - if (lsym != NoSymbol) addMember(lubThisType, lubRefined, lubsym(sym)) - } catch { - case ex: NoCommonType => - } - } - if (lubRefined.decls.isEmpty) lubBase - else { -// println("refined lub of "+ts+"/"+narrowts+" is "+lubRefined+", baseclasses = "+(ts map (_.baseTypeSeq) map (_.toList))) - lubRefined - } - } - existentialAbstraction(tparams, lubType) - } - if (printLubs) { - println(indent + "lub of " + ts + " at depth "+depth)//debug - indent = indent + " " - assert(indent.length <= 100) - } - val res = lub0(ts) - if (printLubs) { - indent = indent dropRight 2 - println(indent + "lub of " + ts + " is " + res)//debug - } - if (ts forall (_.isNotNull)) res.notNull else res - } - - val GlbFailure = new Throwable - - /** A global counter for glb calls in the `specializes' query connected to the `addMembers' - * call in `glb'. There's a possible infinite recursion when `specializes' calls - * memberType, which calls baseTypeSeq, which calls mergePrefixAndArgs, which calls glb. - * The counter breaks this recursion after two calls. - * If the recursion is broken, no member is added to the glb. - */ - private var globalGlbDepth = 0 - private final val globalGlbLimit = 2 - - def glb(ts: List[Type]): Type = try { - glb(ts, lubDepth(ts)) - } finally { - lubResults.clear() - glbResults.clear() - } - - /** The greatest lower bound wrt <:< of a list of types */ - private def glb(ts: List[Type], depth: Int): Type = { - def glb0(ts0: List[Type]): Type = elimSuper(ts0) match { - case List() => AnyClass.tpe - case List(t) => t - case ts @ PolyType(tparams, _) :: _ => - val tparams1 = (tparams, matchingBounds(ts, tparams).transpose).zipped map - ((tparam, bounds) => tparam.cloneSymbol.setInfo(lub(bounds, depth))) - PolyType(tparams1, glb0(matchingInstTypes(ts, tparams1))) - case ts @ MethodType(params, _) :: rest => - MethodType(params, glb0(matchingRestypes(ts, params map (_.tpe)))) - case ts @ NullaryMethodType(_) :: rest => - NullaryMethodType(glb0(matchingRestypes(ts, Nil))) - case ts @ TypeBounds(_, _) :: rest => - TypeBounds(lub(ts map (_.bounds.lo), depth), glb(ts map (_.bounds.hi), depth)) - case ts => - glbResults get (depth, ts) match { - case Some(glbType) => - glbType - case _ => - glbResults((depth, ts)) = NothingClass.tpe - val res = if (depth < 0) NothingClass.tpe else glb1(ts) - glbResults((depth, ts)) = res - res - } - } - def glb1(ts0: List[Type]): Type = { - try { - val (ts, tparams) = stripExistentialsAndTypeVars(ts0) - val glbOwner = commonOwner(ts) - def refinedToParents(t: Type): List[Type] = t match { - case RefinedType(ps, _) => ps flatMap refinedToParents - case _ => List(t) - } - def refinedToDecls(t: Type): List[Scope] = t match { - case RefinedType(ps, decls) => - val dss = ps flatMap refinedToDecls - if (decls.isEmpty) dss else decls :: dss - case _ => List() - } - val ts1 = ts flatMap refinedToParents - val glbBase = intersectionType(ts1, glbOwner) - val glbType = - if (phase.erasedTypes || depth == 0) glbBase - else { - val glbRefined = refinedType(ts1, glbOwner) - val glbThisType = glbRefined.typeSymbol.thisType - def glbsym(proto: Symbol): Symbol = { - val prototp = glbThisType.memberInfo(proto) - val syms = for (t <- ts; - alt <- (t.nonPrivateMember(proto.name).alternatives); - if glbThisType.memberInfo(alt) matches prototp - ) yield alt - val symtypes = syms map glbThisType.memberInfo - assert(!symtypes.isEmpty) - proto.cloneSymbol(glbRefined.typeSymbol).setInfoOwnerAdjusted( - if (proto.isTerm) glb(symtypes, decr(depth)) - else { - def isTypeBound(tp: Type) = tp match { - case TypeBounds(_, _) => true - case _ => false - } - def glbBounds(bnds: List[Type]): TypeBounds = { - val lo = lub(bnds map (_.bounds.lo), decr(depth)) - val hi = glb(bnds map (_.bounds.hi), decr(depth)) - if (lo <:< hi) TypeBounds(lo, hi) - else throw GlbFailure - } - val symbounds = symtypes filter isTypeBound - var result: Type = - if (symbounds.isEmpty) - TypeBounds.empty - else glbBounds(symbounds) - for (t <- symtypes if !isTypeBound(t)) - if (result.bounds containsType t) result = t - else throw GlbFailure - result - }) - } - if (globalGlbDepth < globalGlbLimit) - try { - globalGlbDepth += 1 - val dss = ts flatMap refinedToDecls - for (ds <- dss; val sym <- ds.iterator) - if (globalGlbDepth < globalGlbLimit && !(glbThisType specializes sym)) - try { - addMember(glbThisType, glbRefined, glbsym(sym)) - } catch { - case ex: NoCommonType => - } - } finally { - globalGlbDepth -= 1 - } - if (glbRefined.decls.isEmpty) glbBase else glbRefined - } - existentialAbstraction(tparams, glbType) - } catch { - case GlbFailure => - if (ts forall (t => NullClass.tpe <:< t)) NullClass.tpe - else NothingClass.tpe - } - } - // if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG - - val res = glb0(ts) - - // if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG - - if (ts exists (_.isNotNull)) res.notNull else res - } - - /** The most deeply nested owner that contains all the symbols - * of thistype or prefixless typerefs/singletype occurrences in given type. - */ - private def commonOwner(t: Type): Symbol = { - commonOwnerMap.init - commonOwnerMap.apply(t) - commonOwnerMap.result - } - - /** The most deeply nested owner that contains all the symbols - * of thistype or prefixless typerefs/singletype occurrences in given list - * of types. - */ - private def commonOwner(tps: List[Type]): Symbol = { - // if (settings.debug.value) log("computing common owner of types " + tps)//DEBUG - commonOwnerMap.init - tps foreach { tp => commonOwnerMap.apply(tp); () } - commonOwnerMap.result - } - - /** Compute lub (if variance == 1) or glb (if variance == -1) of given list - * of types `tps'. All types in `tps' are typerefs or singletypes - * with the same symbol. - * Return `Some(x)' if the computation succeeds with result `x'. - * Return `None' if the computation fails. - */ - def mergePrefixAndArgs(tps: List[Type], variance: Int, depth: Int): Option[Type] = tps match { - case List(tp) => - Some(tp) - case TypeRef(_, sym, _) :: rest => - val pres = tps map (_.prefix) // prefix normalizes automatically - val pre = if (variance == 1) lub(pres, depth) else glb(pres, depth) - val argss = tps map (_.normalize.typeArgs) // symbol equality (of the tp in tps) was checked using typeSymbol, which normalizes, so should normalize before retrieving arguments - val capturedParams = new ListBuffer[Symbol] - try { - if (sym == ArrayClass && phase.erasedTypes) { - // special treatment for lubs of array types after erasure: - // if argss contain one value type and some other type, the lub is Object - // if argss contain several reference types, the lub is an array over lub of argtypes - if (argss exists (_.isEmpty)) { - None // something is wrong: an array without a type arg. - } else { - val args = argss map (_.head) - if (args.tail forall (_ =:= args.head)) Some(typeRef(pre, sym, List(args.head))) - else if (args exists (arg => isValueClass(arg.typeSymbol))) Some(ObjectClass.tpe) - else Some(typeRef(pre, sym, List(lub(args)))) - } - } else { - val args = (sym.typeParams, argss.transpose).zipped map { - (tparam, as) => - if (depth == 0) - if (tparam.variance == variance) AnyClass.tpe - else if (tparam.variance == -variance) NothingClass.tpe - else NoType - else - if (tparam.variance == variance) lub(as, decr(depth)) - else if (tparam.variance == -variance) glb(as, decr(depth)) - else { - val l = lub(as, decr(depth)) - val g = glb(as, decr(depth)) - if (l <:< g) l - else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we - // just err on the conservative side, i.e. with a bound that is too high. - // if(!(tparam.info.bounds contains tparam)){ //@M can't deal with f-bounds, see #2251 - - val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l) - capturedParams += qvar - qvar.tpe - } - } - } - if (args contains NoType) None - else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args))) - } - } catch { - case ex: MalformedType => None - case ex: IndexOutOfBoundsException => // transpose freaked out because of irregular argss - // catching just in case (shouldn't happen, but also doesn't cost us) - if (settings.debug.value) log("transposed irregular matrix!?"+ (tps, argss)) - None - } - case SingleType(_, sym) :: rest => - val pres = tps map (_.prefix) - val pre = if (variance == 1) lub(pres, depth) else glb(pres, depth) - try { - Some(singleType(pre, sym)) - } catch { - case ex: MalformedType => None - } - case ExistentialType(tparams, quantified) :: rest => - mergePrefixAndArgs(quantified :: rest, variance, depth) map (existentialAbstraction(tparams, _)) - case _ => - assert(false, tps); None - } - - /** Make symbol `sym' a member of scope `tp.decls' - * where `thistp' is the narrowed owner type of the scope. - */ - def addMember(thistp: Type, tp: Type, sym: Symbol) { - assert(sym != NoSymbol) - // if (settings.debug.value) log("add member " + sym+":"+sym.info+" to "+thistp) //DEBUG - if (!(thistp specializes sym)) { - if (sym.isTerm) - for (alt <- tp.nonPrivateDecl(sym.name).alternatives) - if (specializesSym(thistp, sym, thistp, alt)) - tp.decls unlink alt; - tp.decls enter sym - } - } - - /** All types in list must be polytypes with type parameter lists of - * same length as tparams. - * Returns list of list of bounds infos, where corresponding type - * parameters are renamed to tparams. - */ - private def matchingBounds(tps: List[Type], tparams: List[Symbol]): List[List[Type]] = - tps map { - case PolyType(tparams1, _) if sameLength(tparams1, tparams) => - tparams1 map (tparam => tparam.info.substSym(tparams1, tparams)) - case _ => - throw new NoCommonType(tps) - } - - /** All types in list must be polytypes with type parameter lists of - * same length as tparams. - * Returns list of instance types, where corresponding type - * parameters are renamed to tparams. - */ - private def matchingInstTypes(tps: List[Type], tparams: List[Symbol]): List[Type] = - tps map { - case PolyType(tparams1, restpe) if sameLength(tparams1, tparams) => - restpe.substSym(tparams1, tparams) - case _ => - throw new NoCommonType(tps) - } - - /** All types in list must be method types with equal parameter types. - * Returns list of their result types. - */ - private def matchingRestypes(tps: List[Type], pts: List[Type]): List[Type] = - tps map { - case MethodType(params1, res) if (isSameTypes(params1 map (_.tpe), pts)) => - res - case NullaryMethodType(res) if pts isEmpty => - res - case _ => - throw new NoCommonType(tps) - } - - -// TODO: this desperately needs to be cleaned up -// plan: split into kind inference and subkinding -// every Type has a (cached) Kind - def kindsConform(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): Boolean = checkKindBounds0(tparams, targs, pre, owner, false).isEmpty - - /** Check well-kindedness of type application (assumes arities are already checked) -- @M - * - * This check is also performed when abstract type members become concrete (aka a "type alias") -- then tparams.length==1 - * (checked one type member at a time -- in that case, prefix is the name of the type alias) - * - * Type application is just like value application: it's "contravariant" in the sense that - * the type parameters of the supplied type arguments must conform to the type parameters of - * the required type parameters: - * - their bounds must be less strict - * - variances must match (here, variances are absolute, the variance of a type parameter does not influence the variance of its higher-order parameters) - * - @M TODO: are these conditions correct,sufficient&necessary? - * - * e.g. class Iterable[t, m[+x <: t]] --> the application Iterable[Int, List] is okay, since - * List's type parameter is also covariant and its bounds are weaker than <: Int - */ - def checkKindBounds0(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol, explainErrors: Boolean): List[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] = { - var error = false - - def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz) // instantiate type params that come from outside the abstract type we're currently checking - def transformedBounds(p: Symbol, o: Symbol) = transform(p.info.instantiateTypeParams(tparams, targs).bounds, o) - - /** Check whether <arg>sym1</arg>'s variance conforms to <arg>sym2</arg>'s variance - * - * If <arg>sym2</arg> is invariant, <arg>sym1</arg>'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</arg> to a higher-kinded type conform to the expected params <arg>hkparams</arg> - 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) - if (!(bindHKParams(transformedBounds(hkparam, paramowner)) <:< transform(hkarg.info.bounds, owner))) - stricterBound(hkarg, hkparam) - - if (settings.debug.value) { - log("checkKindBoundsHK base case: "+ hkparam +" declared bounds: "+ transformedBounds(hkparam, paramowner) +" after instantiating earlier hkparams: "+ bindHKParams(transformedBounds(hkparam, paramowner))) - log("checkKindBoundsHK base case: "+ hkarg +" has bounds: "+ transform(hkarg.info.bounds, owner)) - } - } 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)])] - (tparams zip targs).foreach{ case (tparam, targ) if (targ.isHigherKinded || !tparam.typeParams.isEmpty) => - // @M must use the typeParams of the type targ, not the typeParams of the symbol of targ!! - targ.typeSymbolDirect.info // force symbol load for #4205 - val tparamsHO = targ.typeParams - - val (arityMismatches, varianceMismatches, stricterBounds) = - checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) // NOTE: *not* targ.typeSymbol, which normalizes - - if(!explainErrors) {if(error) return List((NoType, NoSymbol, Nil, Nil, Nil))} - else if (arityMismatches.nonEmpty || varianceMismatches.nonEmpty || stricterBounds.nonEmpty) { - errors += ((targ, tparam, arityMismatches, varianceMismatches, stricterBounds)) - } - // case (tparam, targ) => println("no check: "+(tparam, targ, tparam.typeParams.isEmpty)) - case _ => - } - - 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") -} diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 08094d4104..cc63a43ca4 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -12,9 +12,8 @@ import java.lang.Integer.toHexString import scala.collection.{ mutable, immutable } import scala.collection.mutable.{ ListBuffer, ArrayBuffer } -import scala.tools.nsc.io.AbstractFile import scala.annotation.switch -import reflect.generic.PickleBuffer +import scala.reflect.common.pickling.{PickleBuffer, ByteCodecs} /** This abstract class implements a class file parser. * @@ -49,7 +48,7 @@ abstract class ClassfileParser { val global: ClassfileParser.this.global.type = ClassfileParser.this.global } - private object unpickler extends UnPickler { + private object unpickler extends scala.reflect.common.pickling.UnPickler { val global: ClassfileParser.this.global.type = ClassfileParser.this.global } @@ -376,7 +375,7 @@ abstract class ClassfileParser { val len = in.getChar(start + 1) val bytes = new Array[Byte](len) Array.copy(in.buf, start + 3, bytes, 0, len) - val decodedLength = reflect.generic.ByteCodecs.decode(bytes) + val decodedLength = ByteCodecs.decode(bytes) value = bytes.take(decodedLength) values(index) = value } @@ -396,7 +395,7 @@ abstract class ClassfileParser { bytesBuffer ++= in.buf.view(start + 3, start + 3 + len) } val bytes = bytesBuffer.toArray - val decodedLength = reflect.generic.ByteCodecs.decode(bytes) + val decodedLength = ByteCodecs.decode(bytes) value = bytes.take(decodedLength) values(indices.head) = value } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index ac2cd9e996..0eb290c988 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -10,7 +10,6 @@ package classfile import scala.collection.{ mutable, immutable } import mutable.ListBuffer import backend.icode._ -import io.AbstractFile import ClassfileConstants._ import Flags._ diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 131c935a8a..ea1283cfaa 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -10,7 +10,7 @@ package classfile import java.lang.Float.floatToIntBits import java.lang.Double.doubleToLongBits import scala.io.Codec -import reflect.generic.{ PickleBuffer, PickleFormat } +import scala.reflect.common.pickling.{ PickleBuffer, PickleFormat } import scala.collection.mutable.LinkedHashMap import PickleFormat._ import Flags._ @@ -30,6 +30,8 @@ abstract class Pickler extends SubComponent { val phaseName = "pickler" + currentRun + def newPhase(prev: Phase): StdPhase = new PicklePhase(prev) class PicklePhase(prev: Phase) extends StdPhase(prev) { diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala index 536e8e89c1..e69de29bb2 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala @@ -1,77 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package symtab -package classfile - -import Flags._ -import scala.reflect.generic.PickleFormat._ - -/** @author Martin Odersky - * @version 1.0 - */ -abstract class UnPickler extends reflect.generic.UnPickler { - val global: Global - import global._ - - def scan(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) = - new CompileScan(bytes, offset, classRoot, moduleRoot, filename).run() - - class CompileScan(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) - extends Scan(bytes, offset, classRoot, moduleRoot, filename) { - - protected override def debug = settings.debug.value - - // override def noSuchTypeTag(tag: Int, end: Int): Type = { - // tag match { - // case DEBRUIJNINDEXtpe => - // DeBruijnIndex(readNat(), readNat()) - // case _ => - // super.noSuchTypeTag(tag, end) - // } - // } - - override protected def errorMissingRequirement(name: Name, owner: Symbol) = - errorMissingRequirement( - "reference " + (if (name.isTypeName) "type " else "value ") + - name.decode + " of " + owner.tpe.widen + " refers to nonexisting symbol.") - - def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type) = - typer.infer.inferMethodAlternative(fun, List(), argtpes, restpe) - - def newLazyTypeRef(i: Int): LazyType = new LazyTypeRef(i) - def newLazyTypeRefAndAlias(i: Int, j: Int): LazyType = new LazyTypeRefAndAlias(i, j) - - /** A lazy type which when completed returns type at index `i`. */ - private class LazyTypeRef(i: Int) extends LazyType { - private val definedAtRunId = currentRunId - private val p = phase - override def complete(sym: Symbol) : Unit = { - val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType` - if (p != phase) atPhase(p) (sym setInfo tp) - else sym setInfo tp - if (currentRunId != definedAtRunId) sym.setInfo(adaptToNewRunMap(tp)) - } - override def load(sym: Symbol) { complete(sym) } - } - - /** A lazy type which when completed returns type at index `i` and sets alias - * of completed symbol to symbol at index `j`. - */ - private class LazyTypeRefAndAlias(i: Int, j: Int) extends LazyTypeRef(i) { - override def complete(sym: Symbol) { - super.complete(sym) - var alias = at(j, readSymbol) - if (alias.isOverloaded) { - atPhase(currentRun.picklerPhase) { - alias = alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt)) - } - } - sym.asInstanceOf[TermSymbol].setAlias(alias) - } - } - } -} diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 37b81a8fc1..6242a22bfa 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -12,7 +12,7 @@ import java.io.IOException import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, _} import scala.collection.mutable.{HashMap, HashSet} -import classfile.UnPickler +import scala.reflect.common.pickling.UnPickler import ch.epfl.lamp.compiler.msil.Type.TMVarUsage /** diff --git a/src/compiler/scala/tools/nsc/transform/Reifiers.scala b/src/compiler/scala/tools/nsc/transform/Reifiers.scala index 6b0d441ad9..d938a20f2f 100644 --- a/src/compiler/scala/tools/nsc/transform/Reifiers.scala +++ b/src/compiler/scala/tools/nsc/transform/Reifiers.scala @@ -12,7 +12,7 @@ import collection.mutable.HashMap * @author Gilles Dubochet, Lex Spoon */ trait Reifiers { - val symbols: SymbolTable + val symbols: Global import symbols._ private def mkGlobalSymbol(fullname: String, sym: Symbol): reflect.Symbol = diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index ee35cfa267..7550fc3739 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -288,6 +288,12 @@ trait Contexts { self: Analyzer => else throw new TypeError(pos, msg1) } +/*!!! def errorTree(pos: Position, msg: String): ErrorTree = { + error(pos, msg) + ErrorTree(msg) setPos pos + } + */ + def warning(pos: Position, msg: String) = { if (reportGeneralErrors) unit.warning(pos, msg) } |