diff options
Diffstat (limited to 'src/compiler/scala/reflect/internal')
18 files changed, 2102 insertions, 996 deletions
diff --git a/src/compiler/scala/reflect/internal/Chars.scala b/src/compiler/scala/reflect/internal/Chars.scala index 7bd37618ed..f2c90a6721 100644 --- a/src/compiler/scala/reflect/internal/Chars.scala +++ b/src/compiler/scala/reflect/internal/Chars.scala @@ -21,27 +21,31 @@ trait Chars { final val SU = '\u001A' /** Convert a character digit to an Int according to given base, - * -1 if no success */ + * -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 + val num = ( + if (ch <= '9') ch - '0' + else if ('a' <= ch && ch <= 'z') ch - 'a' + 10 + else if ('A' <= ch && ch <= 'Z') ch - 'A' + 10 + else -1 + ) + if (0 <= num && num < base) num else -1 } + /** Buffer for creating '\ u XXXX' strings. */ + private[this] val char2uescapeArray = Array[Char]('\\', 'u', 0, 0, 0, 0) /** 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 + @inline def hexChar(ch: Int): Char = + ( if (ch < 10) '0' else 'A' - 10 ) + ch toChar + + char2uescapeArray(2) = hexChar((c >> 12) ) + char2uescapeArray(3) = hexChar((c >> 8) % 16) + char2uescapeArray(4) = hexChar((c >> 4) % 16) + char2uescapeArray(5) = hexChar((c ) % 16) + + new String(char2uescapeArray) } /** Is character a line break? */ diff --git a/src/compiler/scala/reflect/internal/Constants.scala b/src/compiler/scala/reflect/internal/Constants.scala index 2edb0d1fe6..9c4b2b2245 100644 --- a/src/compiler/scala/reflect/internal/Constants.scala +++ b/src/compiler/scala/reflect/internal/Constants.scala @@ -217,7 +217,7 @@ trait Constants extends api.Constants { } def escapedStringValue: String = { - def escape(text: String): String = (text map escapedChar) mkString "" + def escape(text: String): String = text flatMap escapedChar tag match { case NullTag => "null" case StringTag => "\"" + escape(stringValue) + "\"" diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 4d71d2a769..d3af8e2623 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -6,6 +6,7 @@ package scala.reflect package internal +import annotation.{ switch } import scala.collection.{ mutable, immutable } import Flags._ import PartialFunction._ @@ -60,8 +61,8 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val numericWeight = symbolsMapFilt(ScalaValueClasses, nameToWeight.keySet, nameToWeight) lazy val boxedModule = classesMap(x => getModule(boxedName(x))) lazy val boxedClass = classesMap(x => getClass(boxedName(x))) - lazy val refClass = classesMap(x => getClass("scala.runtime." + x + "Ref")) - lazy val volatileRefClass = classesMap(x => getClass("scala.runtime.Volatile" + x + "Ref")) + lazy val refClass = classesMap(x => getRequiredClass("scala.runtime." + x + "Ref")) + lazy val volatileRefClass = classesMap(x => getRequiredClass("scala.runtime.Volatile" + x + "Ref")) lazy val boxMethod = classesMap(x => valueModuleMethod(x, nme.box)) lazy val unboxMethod = classesMap(x => valueModuleMethod(x, nme.unbox)) @@ -85,12 +86,6 @@ trait Definitions extends reflect.api.StandardDefinitions { def isGetClass(sym: Symbol) = (sym.name == nme.getClass_) && (sym.paramss.isEmpty || sym.paramss.head.isEmpty) - private[Definitions] def fullNameStrings: List[String] = nme.ScalaValueNames map ("scala." + _) - private[Definitions] lazy val fullValueName: Set[Name] = { - val values = nme.ScalaValueNames flatMap (x => List(newTypeName("scala." + x), newTermName("scala." + x))) - values.toSet + newTypeName("scala.AnyVal") - } - lazy val AnyValClass = valueCache(tpnme.AnyVal) lazy val UnitClass = valueCache(tpnme.Unit) lazy val ByteClass = valueCache(tpnme.Byte) @@ -101,9 +96,9 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val FloatClass = valueCache(tpnme.Float) lazy val DoubleClass = valueCache(tpnme.Double) lazy val BooleanClass = valueCache(tpnme.Boolean) - def Boolean_and = getMember(BooleanClass, nme.ZAND) - def Boolean_or = getMember(BooleanClass, nme.ZOR) - def Boolean_not = getMember(BooleanClass, nme.UNARY_!) + lazy val Boolean_and = getMember(BooleanClass, nme.ZAND) + lazy val Boolean_or = getMember(BooleanClass, nme.ZOR) + lazy val Boolean_not = getMember(BooleanClass, nme.UNARY_!) def ScalaValueClassesNoUnit = ScalaValueClasses filterNot (_ eq UnitClass) def ScalaValueClasses: List[Symbol] = List( @@ -151,8 +146,10 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val ScalaPackage = getModule(nme.scala_) lazy val ScalaPackageClass = ScalaPackage.moduleClass - lazy val RuntimePackage = getModule("scala.runtime") + lazy val RuntimePackage = getRequiredModule("scala.runtime") lazy val RuntimePackageClass = RuntimePackage.moduleClass + + lazy val JavaLangEnumClass = getRequiredClass("java.lang.Enum") // convenient one-argument parameter lists lazy val anyparam = List(AnyClass.typeConstructor) @@ -163,17 +160,45 @@ trait Definitions extends reflect.api.StandardDefinitions { private def booltype = BooleanClass.typeConstructor private def inttype = IntClass.typeConstructor private def stringtype = StringClass.typeConstructor + + // Java types + def javaTypeName(jclazz: Class[_]): TypeName = newTypeName(jclazz.getName) + + def javaTypeToValueClass(jtype: Class[_]): Symbol = jtype match { + case java.lang.Void.TYPE => UnitClass + case java.lang.Byte.TYPE => ByteClass + case java.lang.Character.TYPE => CharClass + 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.Boolean.TYPE => BooleanClass + case _ => NoSymbol + } + def valueClassToJavaType(sym: Symbol): Class[_] = sym match { + case UnitClass => java.lang.Void.TYPE + case ByteClass => java.lang.Byte.TYPE + case CharClass => java.lang.Character.TYPE + case ShortClass => java.lang.Short.TYPE + case IntClass => java.lang.Integer.TYPE + case LongClass => java.lang.Long.TYPE + case FloatClass => java.lang.Float.TYPE + case DoubleClass => java.lang.Double.TYPE + case BooleanClass => java.lang.Boolean.TYPE + case _ => null + } // top types lazy val AnyClass = newClass(ScalaPackageClass, tpnme.Any, Nil) setFlag (ABSTRACT) lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.typeConstructor) lazy val ObjectClass = getClass(sn.Object) - lazy val AnyCompanionClass = getClass("scala.AnyCompanion") setFlag (SEALED | ABSTRACT | TRAIT) - lazy val AnyValCompanionClass = getClass("scala.AnyValCompanion") setFlag (SEALED | ABSTRACT | TRAIT) + lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") setFlag (SEALED | ABSTRACT | TRAIT) + lazy val AnyValCompanionClass = getRequiredClass("scala.AnyValCompanion") setFlag (SEALED | ABSTRACT | TRAIT) // bottom types - lazy val RuntimeNothingClass = getClass(ClassfileConstants.SCALA_NOTHING) - lazy val RuntimeNullClass = getClass(ClassfileConstants.SCALA_NULL) + lazy val RuntimeNothingClass = getClass(fulltpnme.RuntimeNothing) + lazy val RuntimeNullClass = getClass(fulltpnme.RuntimeNull) sealed abstract class BottomClassSymbol(name: TypeName, parent: Symbol) extends ClassSymbol(ScalaPackageClass, NoPosition, name) { locally { @@ -194,25 +219,25 @@ trait Definitions extends reflect.api.StandardDefinitions { } // exceptions and other throwables - lazy val ClassCastExceptionClass = getClass("java.lang.ClassCastException") + lazy val ClassCastExceptionClass = getRequiredClass("java.lang.ClassCastException") lazy val IndexOutOfBoundsExceptionClass = getClass(sn.IOOBException) lazy val InvocationTargetExceptionClass = getClass(sn.InvTargetException) - lazy val MatchErrorClass = getClass("scala.MatchError") - lazy val NonLocalReturnControlClass = getClass("scala.runtime.NonLocalReturnControl") + lazy val MatchErrorClass = getRequiredClass("scala.MatchError") + lazy val NonLocalReturnControlClass = getRequiredClass("scala.runtime.NonLocalReturnControl") lazy val NullPointerExceptionClass = getClass(sn.NPException) lazy val ThrowableClass = getClass(sn.Throwable) - lazy val UninitializedErrorClass = getClass("scala.UninitializedFieldError") + lazy val UninitializedErrorClass = getRequiredClass("scala.UninitializedFieldError") // fundamental reference classes lazy val ScalaObjectClass = getMember(ScalaPackageClass, tpnme.ScalaObject) - lazy val PartialFunctionClass = getClass("scala.PartialFunction") - lazy val AbstractPartialFunctionClass = getClass("scala.runtime.AbstractPartialFunction") - lazy val SymbolClass = getClass("scala.Symbol") + lazy val PartialFunctionClass = getRequiredClass("scala.PartialFunction") + lazy val AbstractPartialFunctionClass = getRequiredClass("scala.runtime.AbstractPartialFunction") + lazy val SymbolClass = getRequiredClass("scala.Symbol") lazy val StringClass = getClass(sn.String) lazy val StringModule = StringClass.linkedClassOfClass lazy val ClassClass = getClass(sn.Class) def Class_getMethod = getMember(ClassClass, nme.getMethod_) - lazy val DynamicClass = getClass("scala.Dynamic") + lazy val DynamicClass = getRequiredClass("scala.Dynamic") // fundamental modules lazy val SysPackage = getPackageObject("scala.sys") @@ -223,7 +248,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // Those modules and their module classes lazy val UnqualifiedOwners = UnqualifiedModules.toSet ++ UnqualifiedModules.map(_.moduleClass) - lazy val PredefModule: Symbol = getModule("scala.Predef") + lazy val PredefModule: Symbol = getRequiredModule("scala.Predef") lazy val PredefModuleClass = PredefModule.moduleClass // Note: this is not the type alias AnyRef, it's a val defined in Predef // used by the @specialize annotation. @@ -232,26 +257,37 @@ trait Definitions extends reflect.api.StandardDefinitions { def Predef_identity = getMember(PredefModule, nme.identity) def Predef_conforms = getMember(PredefModule, nme.conforms) def Predef_wrapRefArray = getMember(PredefModule, nme.wrapRefArray) - lazy val ConsoleModule: Symbol = getModule("scala.Console") - lazy val ScalaRunTimeModule: Symbol = getModule("scala.runtime.ScalaRunTime") - lazy val SymbolModule: Symbol = getModule("scala.Symbol") - lazy val Symbol_apply = getMember(SymbolModule, nme.apply) + + /** Is `sym` a member of Predef with the given name? + * Note: DON't replace this by sym == Predef_conforms/etc, as Predef_conforms is a `def` + * which does a member lookup (it can't be a lazy val because we might reload Predef + * during resident compilations). + */ + def isPredefMemberNamed(sym: Symbol, name: Name) = ( + (sym.name == name) && (sym.owner == PredefModule.moduleClass) + ) + + lazy val ConsoleModule: Symbol = getRequiredModule("scala.Console") + lazy val ScalaRunTimeModule: Symbol = getRequiredModule("scala.runtime.ScalaRunTime") + lazy val SymbolModule: Symbol = getRequiredModule("scala.Symbol") + lazy val Symbol_apply = SymbolModule.info decl nme.apply + def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq) - def arrayApplyMethod = getMember(ScalaRunTimeModule, "array_apply") - def arrayUpdateMethod = getMember(ScalaRunTimeModule, "array_update") - def arrayLengthMethod = getMember(ScalaRunTimeModule, "array_length") - def arrayCloneMethod = getMember(ScalaRunTimeModule, "array_clone") - def ensureAccessibleMethod = getMember(ScalaRunTimeModule, "ensureAccessible") + def arrayApplyMethod = getMember(ScalaRunTimeModule, nme.array_apply) + def arrayUpdateMethod = getMember(ScalaRunTimeModule, nme.array_update) + def arrayLengthMethod = getMember(ScalaRunTimeModule, nme.array_length) + def arrayCloneMethod = getMember(ScalaRunTimeModule, nme.array_clone) + def ensureAccessibleMethod = getMember(ScalaRunTimeModule, nme.ensureAccessible) def scalaRuntimeSameElements = getMember(ScalaRunTimeModule, nme.sameElements) // classes with special meanings - lazy val StringAddClass = getClass("scala.runtime.StringAdd") - lazy val ArrowAssocClass = getClass("scala.Predef.ArrowAssoc") + lazy val StringAddClass = getRequiredClass("scala.runtime.StringAdd") + lazy val ArrowAssocClass = getRequiredClass("scala.Predef.ArrowAssoc") lazy val StringAdd_+ = getMember(StringAddClass, nme.PLUS) - lazy val NotNullClass = getClass("scala.NotNull") - lazy val ScalaNumberClass = getClass("scala.math.ScalaNumber") - lazy val TraitSetterAnnotationClass = getClass("scala.runtime.TraitSetter") - lazy val DelayedInitClass = getClass("scala.DelayedInit") + lazy val NotNullClass = getRequiredClass("scala.NotNull") + lazy val ScalaNumberClass = getRequiredClass("scala.math.ScalaNumber") + lazy val TraitSetterAnnotationClass = getRequiredClass("scala.runtime.TraitSetter") + lazy val DelayedInitClass = getRequiredClass("scala.DelayedInit") def delayedInitMethod = getMember(DelayedInitClass, nme.delayedInit) // a dummy value that communicates that a delayedInit call is compiler-generated // from phase UnCurry to phase Constructors @@ -259,14 +295,14 @@ trait Definitions extends reflect.api.StandardDefinitions { // def delayedInitArgVal = EmptyPackageClass.newValue(NoPosition, nme.delayedInitArg) // .setInfo(UnitClass.tpe) - lazy val TypeConstraintClass = getClass("scala.annotation.TypeConstraint") + lazy val TypeConstraintClass = getRequiredClass("scala.annotation.TypeConstraint") lazy val SingletonClass = newClass(ScalaPackageClass, tpnme.Singleton, anyparam) setFlag (ABSTRACT | TRAIT | FINAL) - lazy val SerializableClass = getClass("scala.Serializable") + lazy val SerializableClass = getRequiredClass("scala.Serializable") lazy val JavaSerializableClass = getClass(sn.JavaSerializable) - lazy val ComparableClass = getClass("java.lang.Comparable") - lazy val JavaCloneableClass = getClass("java.lang.Cloneable") - lazy val RemoteInterfaceClass = getClass("java.rmi.Remote") - lazy val RemoteExceptionClass = getClass("java.rmi.RemoteException") + lazy val ComparableClass = getRequiredClass("java.lang.Comparable") + lazy val JavaCloneableClass = getRequiredClass("java.lang.Cloneable") + lazy val RemoteInterfaceClass = getRequiredClass("java.rmi.Remote") + lazy val RemoteExceptionClass = getRequiredClass("java.rmi.RemoteException") lazy val RepeatedParamClass = newCovariantPolyClass( ScalaPackageClass, @@ -286,6 +322,7 @@ trait Definitions extends reflect.api.StandardDefinitions { def isRepeatedParamType(tp: Type) = isScalaRepeatedParamType(tp) || isJavaRepeatedParamType(tp) def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf + def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) def isJavaVarArgs(params: List[Symbol]) = params.nonEmpty && isJavaRepeatedParamType(params.last.tpe) def isScalaVarArgs(params: List[Symbol]) = params.nonEmpty && isScalaRepeatedParamType(params.last.tpe) def isVarArgsList(params: List[Symbol]) = params.nonEmpty && isRepeatedParamType(params.last.tpe) @@ -315,66 +352,92 @@ trait Definitions extends reflect.api.StandardDefinitions { val clazz = newClass(ScalaPackageClass, tpnme.EQUALS_PATTERN_NAME, Nil) clazz setInfo polyType(List(newTypeParam(clazz, 0)), ClassInfoType(anyparam, new Scope, clazz)) } + lazy val MatchingStrategyClass = getRequiredClass("scala.MatchingStrategy") // collections classes - lazy val ConsClass = getClass("scala.collection.immutable.$colon$colon") - lazy val IterableClass = getClass("scala.collection.Iterable") - lazy val IteratorClass = getClass("scala.collection.Iterator") - lazy val ListClass = getClass("scala.collection.immutable.List") - lazy val SeqClass = getClass("scala.collection.Seq") - lazy val StringBuilderClass = getClass("scala.collection.mutable.StringBuilder") - lazy val TraversableClass = getClass("scala.collection.Traversable") - - lazy val ListModule = getModule("scala.collection.immutable.List") + lazy val ConsClass = getRequiredClass("scala.collection.immutable.$colon$colon") + lazy val IterableClass = getRequiredClass("scala.collection.Iterable") + lazy val IteratorClass = getRequiredClass("scala.collection.Iterator") + lazy val ListClass = getRequiredClass("scala.collection.immutable.List") + lazy val SeqClass = getRequiredClass("scala.collection.Seq") + lazy val StringBuilderClass = getRequiredClass("scala.collection.mutable.StringBuilder") + lazy val TraversableClass = getRequiredClass("scala.collection.Traversable") + + lazy val ListModule = getRequiredModule("scala.collection.immutable.List") lazy val List_apply = getMember(ListModule, nme.apply) - lazy val NilModule = getModule("scala.collection.immutable.Nil") - lazy val SeqModule = getModule("scala.collection.Seq") + lazy val NilModule = getRequiredModule("scala.collection.immutable.Nil") + lazy val SeqModule = getRequiredModule("scala.collection.Seq") + lazy val IteratorModule = getRequiredModule("scala.collection.Iterator") + lazy val Iterator_apply = getMember(IteratorModule, nme.apply) // arrays and their members - lazy val ArrayModule = getModule("scala.Array") - def ArrayModule_overloadedApply = getMember(ArrayModule, nme.apply) - lazy val ArrayClass = getClass("scala.Array") - def Array_apply = getMember(ArrayClass, nme.apply) - def Array_update = getMember(ArrayClass, nme.update) - def Array_length = getMember(ArrayClass, nme.length) - lazy val Array_clone = getMember(ArrayClass, nme.clone_) + lazy val ArrayModule = getRequiredModule("scala.Array") + lazy val ArrayModule_overloadedApply = getMember(ArrayModule, nme.apply) + lazy val ArrayClass = getRequiredClass("scala.Array") + lazy val Array_apply = getMember(ArrayClass, nme.apply) + lazy val Array_update = getMember(ArrayClass, nme.update) + lazy val Array_length = getMember(ArrayClass, nme.length) + lazy val Array_clone = getMember(ArrayClass, nme.clone_) // reflection / structural types - lazy val SoftReferenceClass = getClass("java.lang.ref.SoftReference") - lazy val WeakReferenceClass = getClass("java.lang.ref.WeakReference") + lazy val SoftReferenceClass = getRequiredClass("java.lang.ref.SoftReference") + lazy val WeakReferenceClass = getRequiredClass("java.lang.ref.WeakReference") lazy val MethodClass = getClass(sn.MethodAsObject) def methodClass_setAccessible = getMember(MethodClass, nme.setAccessible) - lazy val EmptyMethodCacheClass = getClass("scala.runtime.EmptyMethodCache") - lazy val MethodCacheClass = getClass("scala.runtime.MethodCache") + lazy val EmptyMethodCacheClass = getRequiredClass("scala.runtime.EmptyMethodCache") + lazy val MethodCacheClass = getRequiredClass("scala.runtime.MethodCache") def methodCache_find = getMember(MethodCacheClass, nme.find_) def methodCache_add = getMember(MethodCacheClass, nme.add_) // scala.reflect - lazy val ReflectApiUniverse = getClass("scala.reflect.api.Universe") - lazy val ReflectRuntimeMirror = getModule("scala.reflect.runtime.Mirror") - def freeValueMethod = getMember(ReflectRuntimeMirror, "freeValue") + lazy val ReflectApiUniverse = getRequiredClass("scala.reflect.api.Universe") + lazy val ReflectRuntimeMirror = getRequiredModule("scala.reflect.runtime.Mirror") + def freeValueMethod = getMember(ReflectRuntimeMirror, nme.freeValue) lazy val ReflectPackage = getPackageObject("scala.reflect") - def Reflect_mirror = getMember(ReflectPackage, "mirror") - - - lazy val PartialManifestClass = getClass("scala.reflect.ClassManifest") - lazy val PartialManifestModule = getModule("scala.reflect.ClassManifest") - lazy val FullManifestClass = getClass("scala.reflect.Manifest") - lazy val FullManifestModule = getModule("scala.reflect.Manifest") - lazy val OptManifestClass = getClass("scala.reflect.OptManifest") - lazy val NoManifest = getModule("scala.reflect.NoManifest") + def Reflect_mirror = getMember(ReflectPackage, nme.mirror) + + lazy val PartialManifestClass = getRequiredClass("scala.reflect.ClassManifest") + lazy val PartialManifestModule = getRequiredModule("scala.reflect.ClassManifest") + lazy val FullManifestClass = getRequiredClass("scala.reflect.Manifest") + lazy val FullManifestModule = getRequiredModule("scala.reflect.Manifest") + lazy val OptManifestClass = getRequiredClass("scala.reflect.OptManifest") + lazy val NoManifest = getRequiredModule("scala.reflect.NoManifest") lazy val CodeClass = getClass(sn.Code) lazy val CodeModule = getModule(sn.Code) - def Code_lift = getMember(CodeModule, nme.lift_) + lazy val Code_lift = getMember(CodeModule, nme.lift_) - lazy val ScalaSignatureAnnotation = getClass("scala.reflect.ScalaSignature") - lazy val ScalaLongSignatureAnnotation = getClass("scala.reflect.ScalaLongSignature") + lazy val ScalaSignatureAnnotation = getRequiredClass("scala.reflect.ScalaSignature") + lazy val ScalaLongSignatureAnnotation = getRequiredClass("scala.reflect.ScalaLongSignature") // Option classes - lazy val OptionClass: Symbol = getClass("scala.Option") - lazy val SomeClass: Symbol = getClass("scala.Some") - lazy val NoneModule: Symbol = getModule("scala.None") - lazy val SomeModule: Symbol = getModule("scala.Some") + lazy val OptionClass: Symbol = getRequiredClass("scala.Option") + lazy val SomeClass: Symbol = getRequiredClass("scala.Some") + lazy val NoneModule: Symbol = getRequiredModule("scala.None") + lazy val SomeModule: Symbol = getRequiredModule("scala.Some") + + /** Note: don't use this manifest/type function for anything important, + * as it is incomplete. Would love to have things like existential types + * working, but very unfortunately the manifests just stuff the relevant + * information into the toString method. + */ + def manifestToType(m: OptManifest[_]): Type = m match { + case x: AnyValManifest[_] => + getClassIfDefined("scala." + x).tpe + case m: ClassManifest[_] => + val name = m.erasure.getName + if (name endsWith nme.MODULE_SUFFIX_STRING) + getModuleIfDefined(name stripSuffix nme.MODULE_SUFFIX_STRING).tpe + else { + val sym = getClassIfDefined(name) + val args = m.typeArguments + + if (sym eq NoSymbol) NoType + else if (args.isEmpty) sym.tpe + else appliedType(sym.typeConstructor, args map manifestToType) + } + case _ => + NoType + } // The given symbol represents either String.+ or StringAdd.+ def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+ @@ -406,7 +469,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // Product, Tuple, Function private def mkArityArray(name: String, arity: Int, countFrom: Int = 1): Array[Symbol] = { - val list = countFrom to arity map (i => getClass("scala." + name + i)) + val list = countFrom to arity map (i => getRequiredClass("scala." + name + i)) if (countFrom == 0) list.toArray else (NoSymbol +: list).toArray } @@ -422,10 +485,24 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val FunctionClass = mkArityArray("Function", MaxFunctionArity, 0) lazy val AbstractFunctionClass = mkArityArray("runtime.AbstractFunction", MaxFunctionArity, 0) lazy val isProductNClass = ProductClass.toSet + def wrapArrayMethodName(elemtp: Type): TermName = elemtp.typeSymbol match { + case ByteClass => nme.wrapByteArray + case ShortClass => nme.wrapShortArray + case CharClass => nme.wrapCharArray + case IntClass => nme.wrapIntArray + case LongClass => nme.wrapLongArray + case FloatClass => nme.wrapFloatArray + case DoubleClass => nme.wrapDoubleArray + case BooleanClass => nme.wrapBooleanArray + case UnitClass => nme.wrapUnitArray + case _ => + if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol)) nme.wrapRefArray + else nme.genericWrapArray + } - def tupleField(n: Int, j: Int) = getMember(TupleClass(n), "_" + j) - def isTupleType(tp: Type): Boolean = isTupleType(tp, false) - def isTupleTypeOrSubtype(tp: Type): Boolean = isTupleType(tp, true) + def tupleField(n: Int, j: Int) = getMember(TupleClass(n), nme.productAccessorName(j)) + def isTupleType(tp: Type): Boolean = isTupleType(tp, false) + def isTupleTypeOrSubtype(tp: Type): Boolean = isTupleType(tp, true) private def isTupleType(tp: Type, subtypeOK: Boolean) = tp.normalize match { case TypeRef(_, sym, args) if args.nonEmpty => val len = args.length @@ -444,7 +521,7 @@ trait Definitions extends reflect.api.StandardDefinitions { } else NoType } - lazy val ProductRootClass: Symbol = getClass("scala.Product") + lazy val ProductRootClass: Symbol = getRequiredClass("scala.Product") def Product_productArity = getMember(ProductRootClass, nme.productArity) def Product_productElement = getMember(ProductRootClass, nme.productElement) // def Product_productElementName = getMember(ProductRootClass, nme.productElementName) @@ -513,9 +590,10 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => NoType } - def seqType(arg: Type) = appliedType(SeqClass.typeConstructor, List(arg)) - def arrayType(arg: Type) = appliedType(ArrayClass.typeConstructor, List(arg)) - def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg)) + def seqType(arg: Type) = appliedType(SeqClass.typeConstructor, List(arg)) + def arrayType(arg: Type) = appliedType(ArrayClass.typeConstructor, List(arg)) + def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg)) + def iteratorOfType(tp: Type) = appliedType(IteratorClass.typeConstructor, List(tp)) def ClassType(arg: Type) = if (phase.erasedTypes || forMSIL) ClassClass.tpe @@ -525,7 +603,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // .NET backend // - lazy val ComparatorClass = getClass("scala.runtime.Comparator") + lazy val ComparatorClass = getRequiredClass("scala.runtime.Comparator") // System.ValueType lazy val ValueTypeClass: Symbol = getClass(sn.ValueType) // System.MulticastDelegate @@ -570,10 +648,10 @@ trait Definitions extends reflect.api.StandardDefinitions { var Object_## : Symbol = _ var Object_synchronized: Symbol = _ lazy val Object_isInstanceOf = newPolyMethod( - ObjectClass, "$isInstanceOf", + ObjectClass, newTermName("$isInstanceOf"), tparam => MethodType(List(), booltype)) setFlag (FINAL | SYNTHETIC) lazy val Object_asInstanceOf = newPolyMethod( - ObjectClass, "$asInstanceOf", + ObjectClass, newTermName("$asInstanceOf"), tparam => MethodType(List(), tparam.typeConstructor)) setFlag (FINAL | SYNTHETIC) def Object_getClass = getMember(ObjectClass, nme.getClass_) @@ -588,57 +666,57 @@ trait Definitions extends reflect.api.StandardDefinitions { var String_+ : Symbol = _ // boxed classes - lazy val ObjectRefClass = getClass("scala.runtime.ObjectRef") - lazy val VolatileObjectRefClass = getClass("scala.runtime.VolatileObjectRef") - lazy val BoxesRunTimeClass = getModule("scala.runtime.BoxesRunTime") + lazy val ObjectRefClass = getRequiredClass("scala.runtime.ObjectRef") + lazy val VolatileObjectRefClass = getRequiredClass("scala.runtime.VolatileObjectRef") + lazy val BoxesRunTimeClass = getRequiredModule("scala.runtime.BoxesRunTime") lazy val BoxedNumberClass = getClass(sn.BoxedNumber) lazy val BoxedCharacterClass = getClass(sn.BoxedCharacter) lazy val BoxedBooleanClass = getClass(sn.BoxedBoolean) - lazy val BoxedByteClass = getClass("java.lang.Byte") - lazy val BoxedShortClass = getClass("java.lang.Short") - lazy val BoxedIntClass = getClass("java.lang.Integer") - lazy val BoxedLongClass = getClass("java.lang.Long") - lazy val BoxedFloatClass = getClass("java.lang.Float") - lazy val BoxedDoubleClass = getClass("java.lang.Double") - - lazy val BoxedUnitClass = getClass("scala.runtime.BoxedUnit") - lazy val BoxedUnitModule = getModule("scala.runtime.BoxedUnit") - def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT") - def BoxedUnit_TYPE = getMember(BoxedUnitModule, "TYPE") + lazy val BoxedByteClass = getRequiredClass("java.lang.Byte") + lazy val BoxedShortClass = getRequiredClass("java.lang.Short") + lazy val BoxedIntClass = getRequiredClass("java.lang.Integer") + lazy val BoxedLongClass = getRequiredClass("java.lang.Long") + lazy val BoxedFloatClass = getRequiredClass("java.lang.Float") + lazy val BoxedDoubleClass = getRequiredClass("java.lang.Double") + + lazy val BoxedUnitClass = getRequiredClass("scala.runtime.BoxedUnit") + lazy val BoxedUnitModule = getRequiredModule("scala.runtime.BoxedUnit") + def BoxedUnit_UNIT = getMember(BoxedUnitModule, nme.UNIT) + def BoxedUnit_TYPE = getMember(BoxedUnitModule, nme.TYPE_) // Annotation base classes - lazy val AnnotationClass = getClass("scala.annotation.Annotation") - lazy val ClassfileAnnotationClass = getClass("scala.annotation.ClassfileAnnotation") - lazy val StaticAnnotationClass = getClass("scala.annotation.StaticAnnotation") + lazy val AnnotationClass = getRequiredClass("scala.annotation.Annotation") + lazy val ClassfileAnnotationClass = getRequiredClass("scala.annotation.ClassfileAnnotation") + lazy val StaticAnnotationClass = getRequiredClass("scala.annotation.StaticAnnotation") // Annotations - lazy val BridgeClass = getClass("scala.annotation.bridge") - lazy val ElidableMethodClass = getClass("scala.annotation.elidable") - lazy val ImplicitNotFoundClass = getClass("scala.annotation.implicitNotFound") - lazy val MigrationAnnotationClass = getClass("scala.annotation.migration") - lazy val ScalaStrictFPAttr = getClass("scala.annotation.strictfp") - lazy val SerializableAttr = getClass("scala.annotation.serializable") // @serializable is deprecated - lazy val SwitchClass = getClass("scala.annotation.switch") - lazy val TailrecClass = getClass("scala.annotation.tailrec") - lazy val VarargsClass = getClass("scala.annotation.varargs") - lazy val uncheckedStableClass = getClass("scala.annotation.unchecked.uncheckedStable") - lazy val uncheckedVarianceClass = getClass("scala.annotation.unchecked.uncheckedVariance") - - lazy val BeanPropertyAttr = getClass("scala.beans.BeanProperty") - lazy val BooleanBeanPropertyAttr = getClass("scala.beans.BooleanBeanProperty") - lazy val CloneableAttr = getClass("scala.cloneable") - lazy val DeprecatedAttr = getClass("scala.deprecated") - lazy val DeprecatedNameAttr = getClass("scala.deprecatedName") - lazy val NativeAttr = getClass("scala.native") - lazy val RemoteAttr = getClass("scala.remote") - lazy val ScalaInlineClass = getClass("scala.inline") - lazy val ScalaNoInlineClass = getClass("scala.noinline") - lazy val SerialVersionUIDAttr = getClass("scala.SerialVersionUID") - lazy val SpecializedClass = getClass("scala.specialized") - lazy val ThrowsClass = getClass("scala.throws") - lazy val TransientAttr = getClass("scala.transient") - lazy val UncheckedClass = getClass("scala.unchecked") - lazy val VolatileAttr = getClass("scala.volatile") + lazy val BridgeClass = getRequiredClass("scala.annotation.bridge") + lazy val ElidableMethodClass = getRequiredClass("scala.annotation.elidable") + lazy val ImplicitNotFoundClass = getRequiredClass("scala.annotation.implicitNotFound") + lazy val MigrationAnnotationClass = getRequiredClass("scala.annotation.migration") + lazy val ScalaStrictFPAttr = getRequiredClass("scala.annotation.strictfp") + lazy val SerializableAttr = getRequiredClass("scala.annotation.serializable") // @serializable is deprecated + lazy val SwitchClass = getRequiredClass("scala.annotation.switch") + lazy val TailrecClass = getRequiredClass("scala.annotation.tailrec") + lazy val VarargsClass = getRequiredClass("scala.annotation.varargs") + lazy val uncheckedStableClass = getRequiredClass("scala.annotation.unchecked.uncheckedStable") + lazy val uncheckedVarianceClass = getRequiredClass("scala.annotation.unchecked.uncheckedVariance") + + lazy val BeanPropertyAttr = getRequiredClass("scala.beans.BeanProperty") + lazy val BooleanBeanPropertyAttr = getRequiredClass("scala.beans.BooleanBeanProperty") + lazy val CloneableAttr = getRequiredClass("scala.cloneable") + lazy val DeprecatedAttr = getRequiredClass("scala.deprecated") + lazy val DeprecatedNameAttr = getRequiredClass("scala.deprecatedName") + lazy val NativeAttr = getRequiredClass("scala.native") + lazy val RemoteAttr = getRequiredClass("scala.remote") + lazy val ScalaInlineClass = getRequiredClass("scala.inline") + lazy val ScalaNoInlineClass = getRequiredClass("scala.noinline") + lazy val SerialVersionUIDAttr = getRequiredClass("scala.SerialVersionUID") + lazy val SpecializedClass = getRequiredClass("scala.specialized") + lazy val ThrowsClass = getRequiredClass("scala.throws") + lazy val TransientAttr = getRequiredClass("scala.transient") + lazy val UncheckedClass = getRequiredClass("scala.unchecked") + lazy val VolatileAttr = getRequiredClass("scala.volatile") // Meta-annotations lazy val BeanGetterTargetClass = getMetaAnnotation("beanGetter") @@ -649,7 +727,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val SetterTargetClass = getMetaAnnotation("setter") // TODO: module, moduleClass? package, packageObject? - private def getMetaAnnotation(name: String) = getClass("scala.annotation.meta." + name) + private def getMetaAnnotation(name: String) = getRequiredClass("scala.annotation.meta." + name) def isMetaAnnotation(sym: Symbol): Boolean = metaAnnotations(sym) || ( // Trying to allow for deprecated locations sym.isAliasType && isMetaAnnotation(sym.info.typeSymbol) @@ -667,11 +745,11 @@ trait Definitions extends reflect.api.StandardDefinitions { attr } - def getPackageObjectClass(fullname: Name): Symbol = + def getPackageObjectClass(fullname: String): Symbol = getPackageObject(fullname).companionClass - def getPackageObject(fullname: Name): Symbol = - getModule(fullname).info member nme.PACKAGE + def getPackageObject(fullname: String): Symbol = + getModule(newTermName(fullname)).info member nme.PACKAGE def getModule(fullname: Name): Symbol = getModuleOrClass(fullname.toTermName) @@ -681,11 +759,20 @@ trait Definitions extends reflect.api.StandardDefinitions { while (result.isAliasType) result = result.info.typeSymbol result } - + + def getRequiredModule(fullname: String): Symbol = + getModule(newTermNameCached(fullname)) + def getRequiredClass(fullname: String): Symbol = + getClass(newTypeNameCached(fullname)) + + def getClassIfDefined(fullname: String): Symbol = + getClassIfDefined(newTypeName(fullname)) def getClassIfDefined(fullname: Name): Symbol = try getClass(fullname.toTypeName) catch { case _: MissingRequirementError => NoSymbol } + def getModuleIfDefined(fullname: String): Symbol = + getModuleIfDefined(newTermName(fullname)) def getModuleIfDefined(fullname: Name): Symbol = try getModule(fullname.toTermName) catch { case _: MissingRequirementError => NoSymbol } @@ -914,8 +1001,7 @@ trait Definitions extends reflect.api.StandardDefinitions { ObjectClass, nme.synchronized_, tparam => msym => MethodType(msym.newSyntheticValueParams(List(tparam.typeConstructor)), tparam.typeConstructor)) setFlag FINAL - String_+ = newMethod( - StringClass, "+", anyparam, stringtype) setFlag FINAL + String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype) setFlag FINAL val forced = List( // force initialization of every symbol that is entered as a side effect AnnotationDefaultAttr, // #2264 @@ -948,7 +1034,7 @@ trait Definitions extends reflect.api.StandardDefinitions { assert(forMSIL, "scalaCallers can only be created if target is .NET") // object: reference to object on which to call (scala-)method val paramTypes: List[Type] = List(ObjectClass.tpe) - val name: String = "$scalaCaller$$" + nbScalaCallers + val name = newTermName("$scalaCaller$$" + nbScalaCallers) // tparam => resultType, which is the resultType of PolyType, i.e. the result type after applying the // type parameter =-> a MethodType in this case // TODO: set type bounds manually (-> MulticastDelegate), see newTypeParam diff --git a/src/compiler/scala/reflect/internal/Flags.scala b/src/compiler/scala/reflect/internal/Flags.scala index 8366c6d63a..9e4f0431c3 100644 --- a/src/compiler/scala/reflect/internal/Flags.scala +++ b/src/compiler/scala/reflect/internal/Flags.scala @@ -7,6 +7,7 @@ package scala.reflect package internal import api.Modifier +import scala.collection.{ mutable, immutable } // 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 @@ -225,6 +226,7 @@ class Flags extends ModifierFlags { /** The two bridge flags */ final val BridgeFlags = BRIDGE | VBRIDGE + final val BridgeAndPrivateFlags = BridgeFlags | PRIVATE /** When a symbol for a field is created, only these flags survive * from Modifiers. Others which may be applied at creation time are: @@ -426,8 +428,29 @@ class Flags extends ModifierFlags { List(flagsToString(f), pw) filterNot (_ == "") mkString " " } - def flagsToString(flags: Long): String = - pickledListOrder map (mask => flagToString(flags & mask)) filterNot (_ == "") mkString " " + // List of the raw flags, in pickled order + protected final val MaxBitPosition = 62 + + def flagsToString(flags: Long): String = { + // Fast path for common case + if (flags == 0L) "" else { + var sb: StringBuilder = null + var i = 0 + while (i <= MaxBitPosition) { + val mask = rawFlagPickledOrder(i) + if ((flags & mask) != 0L) { + val s = flagToString(mask) + if (s.length > 0) { + if (sb eq null) sb = new StringBuilder append s + else if (sb.length == 0) sb append s + else sb append " " append s + } + } + i += 1 + } + if (sb eq null) "" else sb.toString + } + } def rawFlagsToPickled(flags: Long): Long = (flags & ~PKL_MASK) | r2p(flags.toInt & PKL_MASK) @@ -435,13 +458,13 @@ class Flags extends ModifierFlags { def pickledToRawFlags(pflags: Long): Long = (pflags & ~PKL_MASK) | p2r(pflags.toInt & PKL_MASK) - // List of the raw flags, in pickled order - protected val pickledListOrder: List[Long] = { - val all = 0 to 62 map (1L << _) + protected final val pickledListOrder: List[Long] = { + val all = 0 to MaxBitPosition map (1L << _) val front = rawFlags map (_.toLong) front.toList ++ (all filterNot (front contains _)) } + protected final val rawFlagPickledOrder: Array[Long] = pickledListOrder.toArray def flagOfModifier(mod: Modifier.Value): Long = mod match { case Modifier.`protected` => PROTECTED diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index 60b353a7c4..38f808cef9 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -20,8 +20,8 @@ trait Importers { self: SymbolTable => def importSymbol(sym: from.Symbol): Symbol = { def doImport(sym: from.Symbol): Symbol = { val myowner = importSymbol(sym.owner) - val mypos = importPosition(sym.pos) - val myname = importName(sym.name) + val mypos = importPosition(sym.pos) + val myname = importName(sym.name).toTermName def linkReferenced(mysym: TermSymbol, x: from.TermSymbol, op: from.Symbol => Symbol): Symbol = { symMap(x) = mysym mysym.referenced = op(x.referenced) @@ -33,7 +33,7 @@ trait Importers { self: SymbolTable => case x: from.ModuleSymbol => linkReferenced(new ModuleSymbol(myowner, mypos, myname), x, doImport) case x: from.FreeVar => - new FreeVar(importName(x.name), importType(x.tpe), x.value) + new FreeVar(importName(x.name).toTermName, importType(x.tpe), x.value) case x: from.TermSymbol => linkReferenced(new TermSymbol(myowner, mypos, myname), x, importSymbol) case x: from.TypeSkolem => @@ -161,13 +161,13 @@ trait Importers { self: SymbolTable => case from.RefinedType(parents, decls) => RefinedType(parents map importType, importScope(decls), importSymbol(tpe.typeSymbol)) case from.ExistentialType(tparams, restpe) => - ExistentialType(tparams map importSymbol, importType(restpe)) + newExistentialType(tparams map importSymbol, importType(restpe)) case from.OverloadedType(pre, alts) => OverloadedType(importType(pre), alts map importSymbol) case from.AntiPolyType(pre, targs) => AntiPolyType(importType(pre), targs map importType) case x: from.TypeVar => - new TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol) + TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol) case from.NotNullType(tpe) => NotNullType(importType(tpe)) case from.AnnotatedType(annots, tpe, selfsym) => diff --git a/src/compiler/scala/reflect/internal/Kinds.scala b/src/compiler/scala/reflect/internal/Kinds.scala new file mode 100644 index 0000000000..e675be43dc --- /dev/null +++ b/src/compiler/scala/reflect/internal/Kinds.scala @@ -0,0 +1,221 @@ +/* NSC -- new scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package internal + +import scala.collection.{ mutable, immutable } +import scala.tools.util.StringOps.{ countAsString, countElementsAsString } + +trait Kinds { + self: SymbolTable => + + import definitions._ + + private type SymPair = ((Symbol, Symbol)) // ((Argument, Parameter)) + + case class KindErrors( + arity: List[SymPair] = Nil, + variance: List[SymPair] = Nil, + strictness: List[SymPair] = Nil + ) { + def isEmpty = arity.isEmpty && variance.isEmpty && strictness.isEmpty + + def arityError(syms: SymPair) = copy(arity = arity :+ syms) + def varianceError(syms: SymPair) = copy(variance = variance :+ syms) + def strictnessError(syms: SymPair) = copy(strictness = strictness :+ syms) + + def ++(errs: KindErrors) = KindErrors( + arity ++ errs.arity, + variance ++ errs.variance, + strictness ++ errs.strictness + ) + // @M TODO this method is duplicated all over the place (varianceString) + private def varStr(s: Symbol): String = + if (s.isCovariant) "covariant" + else if (s.isContravariant) "contravariant" + else "invariant"; + + private def qualify(a0: Symbol, b0: Symbol): String = if (a0.toString != b0.toString) "" else { + if((a0 eq b0) || (a0.owner eq b0.owner)) "" + else { + var a = a0; var b = b0 + while (a.owner.name == b.owner.name) { a = a.owner; b = b.owner} + if (a.locationString ne "") " (" + a.locationString.trim + ")" else "" + } + } + private def kindMessage(a: Symbol, p: Symbol)(f: (String, String) => String): String = + f(a+qualify(a,p), p+qualify(p,a)) + + private def strictnessMessage(a: Symbol, p: Symbol) = + kindMessage(a, p)("%s's bounds %s are stricter than %s's declared bounds %s".format( + _, a.info, _, p.info)) + + private def varianceMessage(a: Symbol, p: Symbol) = + kindMessage(a, p)("%s is %s, but %s is declared %s".format(_, varStr(a), _, varStr(p))) + + private def arityMessage(a: Symbol, p: Symbol) = + kindMessage(a, p)("%s has %s, but %s has %s".format( + _, countElementsAsString(a.typeParams.length, "type parameter"), + _, countAsString(p.typeParams.length)) + ) + + def errorMessage(targ: Type, tparam: Symbol): String = ( + (targ+"'s type parameters do not match "+tparam+"'s expected parameters: ") + + (arity map { case (a, p) => arityMessage(a, p) } mkString ", ") + + (variance map { case (a, p) => varianceMessage(a, p) } mkString ", ") + + (strictness map { case (a, p) => strictnessMessage(a, p) } mkString ", ") + ) + } + val NoKindErrors = KindErrors(Nil, Nil, Nil) + + // 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 whether `sym1`'s variance conforms to `sym2`'s variance. + * + * If `sym2` is invariant, `sym1`'s variance is irrelevant. Otherwise they must be equal. + */ + private def variancesMatch(sym1: Symbol, sym2: Symbol) = ( + sym2.variance==0 + || sym1.variance==sym2.variance + ) + + /** 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, KindErrors)] = { + + // instantiate type params that come from outside the abstract type we're currently checking + def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz) + + // check that the type parameters hkargs to a higher-kinded type conform to the + // expected params hkparams + def checkKindBoundsHK( + hkargs: List[Symbol], + arg: Symbol, + param: Symbol, + paramowner: Symbol, + underHKParams: List[Symbol], + withHKArgs: List[Symbol] + ): KindErrors = { + + var kindErrors: KindErrors = NoKindErrors + 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 + + def kindCheck(cond: Boolean, f: KindErrors => KindErrors) { + if (!cond) + kindErrors = f(kindErrors) + } + + 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)) { + // Any and Nothing are kind-overloaded + if (arg == AnyClass || arg == NothingClass) NoKindErrors + // shortcut: always set error, whether explainTypesOrNot + else return kindErrors.arityError(arg -> param) + } + else foreach2(hkargs, hkparams) { (hkarg, hkparam) => + if (hkparam.typeParams.isEmpty && hkarg.typeParams.isEmpty) { // base-case: kind * + kindCheck(variancesMatch(hkarg, hkparam), _ varianceError (hkarg -> hkparam)) + // instantiateTypeParams(tparams, targs) + // higher-order bounds, may contain references to type arguments + // substSym(hkparams, hkargs) + // these types are going to be compared as types of kind * + // + // Their arguments use different symbols, but are + // conceptually the same. Could also replace the types by + // polytypes, but can't just strip the symbols, as ordering + // is lost then. + val declaredBounds = transform(hkparam.info.instantiateTypeParams(tparams, targs).bounds, paramowner) + val declaredBoundsInst = transform(bindHKParams(declaredBounds), owner) + val argumentBounds = transform(hkarg.info.bounds, owner) + + kindCheck(declaredBoundsInst <:< argumentBounds, _ strictnessError (hkarg -> hkparam)) + + debuglog( + "checkKindBoundsHK base case: " + hkparam + + " declared bounds: " + declaredBounds + + " after instantiating earlier hkparams: " + declaredBoundsInst + "\n" + + "checkKindBoundsHK base case: "+ hkarg + + " has bounds: " + argumentBounds + ) + } + else { + debuglog("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg) + kindErrors ++= checkKindBoundsHK( + hkarg.typeParams, + hkarg, + hkparam, + paramowner, + underHKParams ++ hkparam.typeParams, + withHKArgs ++ hkarg.typeParams + ) + } + if (!explainErrors && !kindErrors.isEmpty) + return kindErrors + } + if (explainErrors) kindErrors + else NoKindErrors + } + + if (settings.debug.value && (tparams.nonEmpty || targs.nonEmpty)) log( + "checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", " + + owner + ", " + explainErrors + ")" + ) + + flatMap2(tparams, targs) { (tparam, targ) => + // Prevent WildcardType from causing kind errors, as typevars may be higher-order + if (targ == WildcardType) Nil else { + // force symbol load for #4205 + targ.typeSymbolDirect.info + // @M must use the typeParams of the *type* targ, not of the *symbol* of targ!! + val tparamsHO = targ.typeParams + if (targ.isHigherKinded || tparam.typeParams.nonEmpty) { + // NOTE: *not* targ.typeSymbol, which normalizes + val kindErrors = checkKindBoundsHK( + tparamsHO, targ.typeSymbolDirect, tparam, + tparam.owner, tparam.typeParams, tparamsHO + ) + if (kindErrors.isEmpty) Nil else { + if (explainErrors) List((targ, tparam, kindErrors)) + // Return as soon as an error is seen if there's nothing to explain. + else return List((NoType, NoSymbol, NoKindErrors)) + } + } + else Nil + } + } + } +}
\ No newline at end of file diff --git a/src/compiler/scala/reflect/internal/NameManglers.scala b/src/compiler/scala/reflect/internal/NameManglers.scala index 01a93c0ada..ef092f16bb 100644 --- a/src/compiler/scala/reflect/internal/NameManglers.scala +++ b/src/compiler/scala/reflect/internal/NameManglers.scala @@ -22,7 +22,10 @@ trait NameManglers { val MODULE_SUFFIX_STRING = NameTransformer.MODULE_SUFFIX_STRING val NAME_JOIN_STRING = NameTransformer.NAME_JOIN_STRING - + + val MODULE_SUFFIX_NAME: TermName = newTermName(MODULE_SUFFIX_STRING) + val NAME_JOIN_NAME: TermName = newTermName(NAME_JOIN_STRING) + def flattenedName(segments: Name*): NameType = compactedString(segments mkString NAME_JOIN_STRING) /** @@ -72,10 +75,13 @@ trait NameManglers { val LOCALDUMMY_PREFIX = "<local " // owner of local blocks val PROTECTED_PREFIX = "protected$" val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set" - val SETTER_SUFFIX = encode("_=") val SINGLETON_SUFFIX = ".type" + val SPECIALIZED_SUFFIX_STRING = "$sp" val SUPER_PREFIX_STRING = "super$" val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$" + + val SETTER_SUFFIX: TermName = encode("_=") + val SPECIALIZED_SUFFIX_NAME: TermName = SPECIALIZED_SUFFIX_STRING def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX @@ -88,7 +94,7 @@ trait NameManglers { 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 isModuleName(name: Name) = name endsWith MODULE_SUFFIX_STRING + def isModuleName(name: Name) = name endsWith MODULE_SUFFIX_NAME def isOpAssignmentName(name: Name) = name match { case raw.NE | raw.LE | raw.GE | EMPTY => false @@ -112,6 +118,17 @@ trait NameManglers { name.subName(i, name.length) } else name } + + def unspecializedName(name: Name): Name = ( + if (name endsWith SPECIALIZED_SUFFIX_NAME) + name.subName(0, name.lastIndexOf('m') - 1) + else name + ) + + def macroMethodName(name: Name) = { + val base = if (name.isTypeName) nme.TYPEkw else nme.DEFkw + base append nme.MACRO append name + } /** Return the original name and the types on which this name * is specialized. For example, @@ -123,8 +140,8 @@ trait NameManglers { * 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" + if (name endsWith SPECIALIZED_SUFFIX_NAME) { + val name1 = name dropRight SPECIALIZED_SUFFIX_NAME.length val idxC = name1 lastIndexOf 'c' val idxM = name1 lastIndexOf 'm' @@ -135,16 +152,18 @@ trait NameManglers { (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 getterToLocal(name: TermName): TermName = name append LOCAL_SUFFIX_STRING + def getterToSetter(name: TermName): TermName = name append SETTER_SUFFIX + def localToGetter(name: TermName): TermName = name dropRight LOCAL_SUFFIX_STRING.length + + def dropLocalSuffix(name: Name): Name = if (name endsWith ' ') name dropRight 1 else name 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)) + setterToGetter(name drop (p + TRAIT_SETTER_SEPARATOR_STRING.length)) else - name stripEnd SETTER_SUFFIX toTermName + name.subName(0, name.length - SETTER_SUFFIX.length) } def defaultGetterName(name: Name, pos: Int): TermName = { @@ -153,8 +172,8 @@ trait NameManglers { } def defaultGetterToMethod(name: Name): TermName = { val p = name.pos(DEFAULT_GETTER_STRING) - if (p < name.length) name.subName(0, p) - else name + if (p < name.length) name.toTermName.subName(0, p) + else name.toTermName } /** !!! I'm putting this logic in place because I can witness @@ -178,18 +197,14 @@ trait NameManglers { } def stripModuleSuffix(name: Name): Name = ( - if (isModuleName(name)) name stripEnd MODULE_SUFFIX_STRING else name + if (isModuleName(name)) name dropRight MODULE_SUFFIX_STRING.length else name ) - /** Note that for performance reasons, stripEnd does not verify that the - * suffix is actually the suffix specified. - */ - def dropSingletonName(name: Name): TypeName = name stripEnd SINGLETON_SUFFIX toTypeName + def dropSingletonName(name: Name): TypeName = name dropRight SINGLETON_SUFFIX.length 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 interfaceName(implname: Name): TypeName = implname dropRight IMPL_CLASS_SUFFIX.length 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. */ diff --git a/src/compiler/scala/reflect/internal/Names.scala b/src/compiler/scala/reflect/internal/Names.scala index a6fd2adb34..b960695f51 100644 --- a/src/compiler/scala/reflect/internal/Names.scala +++ b/src/compiler/scala/reflect/internal/Names.scala @@ -71,39 +71,54 @@ trait Names extends api.Names { } /** Create a term name from the characters in cs[offset..offset+len-1]. */ - def newTermName(cs: Array[Char], offset: Int, len: Int): TermName = { + def newTermName(cs: Array[Char], offset: Int, len: Int): TermName = + newTermName(cs, offset, len, cachedString = null) + + def newTermName(cs: Array[Char]): TermName = newTermName(cs, 0, cs.length) + def newTypeName(cs: Array[Char]): TypeName = newTypeName(cs, 0, cs.length) + + /** Create a term name from the characters in cs[offset..offset+len-1]. */ + protected def newTermName(cs: Array[Char], offset: Int, len: Int, cachedString: String): 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) { + + if (n ne null) n + else { // The logic order here is future-proofing against the possibility // that name.toString will become an eager val, in which case the call // to enterChars cannot follow the construction of the TermName. val ncStart = nc enterChars(cs, offset, len) - n = new TermName(ncStart, len, h) + if (cachedString ne null) new TermName_S(ncStart, len, h, cachedString) + else new TermName_R(ncStart, len, h) } - n } + protected def newTypeName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TypeName = + newTermName(cs, offset, len, cachedString).toTypeName /** Create a term name from string. */ - def newTermName(s: String): TermName = - newTermName(s.toCharArray(), 0, s.length()) + def newTermName(s: String): TermName = newTermName(s.toCharArray(), 0, s.length(), null) + + /** Create a type name from string. */ + def newTypeName(s: String): TypeName = newTermName(s).toTypeName /** 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 = { - val chars = Codec fromUTF8 bs.slice(offset, offset + len) + val chars = Codec.fromUTF8(bs, offset, len) newTermName(chars, 0, chars.length) } + def newTermNameCached(s: String): TermName = + newTermName(s.toCharArray(), 0, s.length(), cachedString = s) + + def newTypeNameCached(s: String): TypeName = + newTypeName(s.toCharArray(), 0, s.length(), cachedString = s) + /** 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 + newTermName(cs, offset, len, cachedString = null).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 = @@ -114,19 +129,27 @@ trait Names extends api.Names { // Classes ---------------------------------------------------------------------- - /** The name class. */ + /** The name class. + * TODO - resolve schizophrenia regarding whether to treat Names as Strings + * or Strings as Names. Give names the key functions the absence of which + * make people want Strings all the time. + */ sealed abstract class Name(protected val index: Int, protected val len: Int) extends AbsName with Function1[Int, Char] { + type ThisNameType <: Name + protected[this] def thisName: ThisNameType + /** Index into name table */ def start: Int = index /** The next name in the same hash bucket. */ - def next: Name + def next: ThisNameType /** The length of this name. */ final def length: Int = len final def isEmpty = length == 0 final def nonEmpty = !isEmpty + def nameKind: String def isTermName: Boolean def isTypeName: Boolean def toTermName: TermName @@ -134,6 +157,15 @@ trait Names extends api.Names { def companionName: Name def bothNames: List[Name] = List(toTermName, toTypeName) + /** Return the subname with characters from from to to-1. */ + def subName(from: Int, to: Int): ThisNameType + + /** Return a new name of the same variety. */ + def newName(str: String): ThisNameType + + /** Return a new name based on string transformation. */ + def mapName(f: String => String): ThisNameType = newName(f(toString)) + /** 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) @@ -145,21 +177,13 @@ trait Names extends api.Names { cs } - /** @return the string representation of this name */ - final override def toString(): String = new String(chrs, index, len) - // Should we opt to make toString into a val to avoid the creation - // of 750,000 copies of x$1, here's the line. - // final override val toString = 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) + val bytes = Codec.toUTF8(chrs, index, len) compat.Platform.arraycopy(bytes, 0, bs, offset, bytes.length) offset + bytes.length } @@ -306,6 +330,16 @@ trait Names extends api.Names { while (start <= last && !startsWith(subname, start)) start += 1 start <= last } + final def containsChar(ch: Char): Boolean = { + var i = index + val max = index + len + while (i < max) { + if (chrs(i) == ch) + return true + i += 1 + } + false + } /** Some thoroughly self-explanatory convenience functions. They * assume that what they're being asked to do is known to be valid. @@ -316,15 +350,20 @@ trait Names extends api.Names { 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 from to to-1. */ - def subName(from: Int, to: Int): Name + def dropRight(n: Int) = subName(0, len - n) + def drop(n: Int) = subName(n, len) + + def indexOf(ch: Char) = { + val idx = pos(ch) + if (idx == length) -1 else idx + } + def indexOf(ch: Char, fromIndex: Int) = { + val idx = pos(ch, fromIndex) + if (idx == length) -1 else idx + } + def lastIndexOf(ch: Char) = lastPos(ch) + def lastIndexOf(ch: Char, fromIndex: Int) = lastPos(ch, fromIndex) /** Replace all occurrences of `from` by `to` in * name; result is always a term name. @@ -339,30 +378,79 @@ trait Names extends api.Names { } newTermName(cs, 0, len) } + + /** TODO - reconcile/fix that encode returns a Name but + * decode returns a String. + */ /** Replace operator symbols by corresponding $op_name. */ - def encode: Name = { + def encode: ThisNameType = { val str = toString val res = NameTransformer.encode(str) - if (res == str) this - else if (isTypeName) newTypeName(res) - else newTermName(res) + if (res == str) thisName else newName(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 decode: String = { + if (this containsChar '$') { + val str = toString + val res = NameTransformer.decode(str) + if (res == str) str + else res + } + else toString + } + + /** TODO - find some efficiency. */ + def append(ch: Char) = newName("" + this + ch) + def append(suffix: String) = newName("" + this + suffix) + def append(suffix: Name) = newName("" + this + suffix) + def prepend(ch: Char) = newName("" + ch + this) + def prepend(prefix: String) = newName("" + prefix + this) + def prepend(prefix: Name) = newName("" + prefix + this) + def decodedName: ThisNameType = newName(decode) def isOperatorName: Boolean = decode != toString - def nameKind: String = if (isTypeName) "type" else "term" - def longString: String = nameKind + " " + NameTransformer.decode(toString) + def longString: String = nameKind + " " + decode + def debugString = { val s = decode ; if (isTypeName) s + "!" else s } + } + + /** A name that contains no operator chars nor dollar signs. + * TODO - see if it's any faster to do something along these lines. + */ + trait AlphaNumName extends Name { + final override def encode = thisName + final override def decodedName = thisName + final override def decode = toString + final override def isOperatorName = false } - final class TermName(_index: Int, _len: Int, hash: Int) extends Name(_index, _len) { + /** TermName_S and TypeName_S have fields containing the string version of the name. + * TermName_R and TypeName_R recreate it each time toString is called. + */ + private class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { + protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString) + override def newName(str: String): TermName = newTermNameCached(str) + } + private class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { + protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString) + override def newName(str: String): TypeName = newTypeNameCached(str) + } + + private class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { + protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h) + override def toString = new String(chrs, index, len) + } + + private class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { + protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h) + override def toString = new String(chrs, index, len) + } + + sealed abstract class TermName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) { + type ThisNameType = TermName + protected[this] def thisName: TermName = this + var next: TermName = termHashtable(hash) termHashtable(hash) = this def isTermName: Boolean = true @@ -372,19 +460,24 @@ trait Names extends api.Names { 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 + n = n.next + + if (n ne null) n + else createCompanionName(h) } - def append(suffix: String): TermName = newTermName(this + suffix) - def append(suffix: Name): TermName = append(suffix.toString) + def newName(str: String): TermName = newTermName(str) def companionName: TypeName = toTypeName def subName(from: Int, to: Int): TermName = newTermName(chrs, start + from, to - from) + + def nameKind = "term" + protected def createCompanionName(h: Int): TypeName } - final class TypeName(_index: Int, _len: Int, hash: Int) extends Name(_index, _len) { + sealed abstract class TypeName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) { + type ThisNameType = TypeName + protected[this] def thisName: TypeName = this + var next: TypeName = typeHashtable(hash) typeHashtable(hash) = this def isTermName: Boolean = false @@ -393,17 +486,19 @@ trait Names extends api.Names { 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 + n = n.next + + if (n ne null) n + else createCompanionName(h) } def toTypeName: TypeName = this - - def append(suffix: String): TypeName = newTypeName(this + suffix) - def append(suffix: Name): TypeName = append(suffix.toString) + def newName(str: String): TypeName = newTypeName(str) def companionName: TermName = toTermName def subName(from: Int, to: Int): TypeName = newTypeName(chrs, start + from, to - from) + + def nameKind = "type" + override def decode = if (nameDebug) super.decode + "!" else super.decode + protected def createCompanionName(h: Int): TermName } } diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index 8afe276514..ea5565c581 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -8,18 +8,21 @@ package internal import scala.collection.immutable import NameTransformer.MODULE_SUFFIX_STRING +import annotation.switch -trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: SymbolTable => +trait StdNames extends NameManglers { self: SymbolTable => - def encode(str: String): TermName = newTermName(NameTransformer.encode(str)) + def encode(str: String): TermName = newTermNameCached(NameTransformer.encode(str)) + + implicit def lowerTermNames(n: TermName): String = "" + n - implicit def stringToTermName(s: String): TermName = newTermName(s) + // 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) + val result = newTermNameCached(s) kws = kws + result result } @@ -87,7 +90,7 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy trait CommonNames /*extends LibraryCommonNames*/ { type NameType <: Name - implicit def createNameType(name: String): NameType + protected implicit def createNameType(name: String): NameType val EMPTY: NameType = "" val ANON_FUN_NAME: NameType = "$anonfun" @@ -146,6 +149,10 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy final val String: NameType = "String" final val Throwable: NameType = "Throwable" + final val Annotation: NameType = "Annotation" + final val ClassfileAnnotation: NameType = "ClassfileAnnotation" + final val Enum: NameType = "Enum" + // Annotation simple names, used in Namer final val BeanPropertyAnnot: NameType = "BeanProperty" final val BooleanBeanPropertyAnnot: NameType = "BooleanBeanProperty" @@ -172,123 +179,191 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy final val SyntheticATTR: NameType = "Synthetic" } - trait TermNames extends Keywords with CommonNames { // Compiler internal names + val EXPAND_SEPARATOR_STRING = "$$" + val ANYNAME: NameType = "<anyname>" val CONSTRUCTOR: NameType = "<init>" val FAKE_LOCAL_THIS: NameType = "this$" val INITIALIZER: NameType = CONSTRUCTOR // Is this buying us something? + val LAZY_LOCAL: NameType = "$lzy" + val LOCAL_SUFFIX_STRING = " " + val MACRO: NameType = "macro$" + val MIRROR_PREFIX: NameType = "$mr." + val MIRROR_SHORT: NameType = "$mr" val MIXIN_CONSTRUCTOR: NameType = "$init$" val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$" val OUTER: NameType = "$outer" - val OUTER_LOCAL: NameType = "$outer " // note the space + val OUTER_LOCAL: NameType = OUTER + LOCAL_SUFFIX_STRING // "$outer ", note the space val OUTER_SYNTH: NameType = "<outer>" // emitted by virtual pattern matcher, replaced by outer accessor in explicitouter + val SELECTOR_DUMMY: NameType = "<unapply-selector>" val SELF: NameType = "$this" val SPECIALIZED_INSTANCE: NameType = "specInstance$" val STAR: NameType = "*" val THIS: NameType = "_$this" - val SELECTOR_DUMMY: NameType = "<unapply-selector>" final val Nil: NameType = "Nil" final val Predef: NameType = "Predef" final val ScalaRunTime: NameType = "ScalaRunTime" final val Some: NameType = "Some" + + val _1 : NameType = "_1" + val _2 : NameType = "_2" + val _3 : NameType = "_3" + val _4 : NameType = "_4" + val _5 : NameType = "_5" + val _6 : NameType = "_6" + val _7 : NameType = "_7" + val _8 : NameType = "_8" + val _9 : NameType = "_9" + val _10 : NameType = "_10" + val _11 : NameType = "_11" + val _12 : NameType = "_12" + val _13 : NameType = "_13" + val _14 : NameType = "_14" + val _15 : NameType = "_15" + val _16 : NameType = "_16" + val _17 : NameType = "_17" + val _18 : NameType = "_18" + val _19 : NameType = "_19" + val _20 : NameType = "_20" + val _21 : NameType = "_21" + val _22 : NameType = "_22" + + val wrapRefArray: NameType = "wrapRefArray" + val wrapByteArray: NameType = "wrapByteArray" + val wrapShortArray: NameType = "wrapShortArray" + val wrapCharArray: NameType = "wrapCharArray" + val wrapIntArray: NameType = "wrapIntArray" + val wrapLongArray: NameType = "wrapLongArray" + val wrapFloatArray: NameType = "wrapFloatArray" + val wrapDoubleArray: NameType = "wrapDoubleArray" + val wrapBooleanArray: NameType = "wrapBooleanArray" + val wrapUnitArray: NameType = "wrapUnitArray" + val genericWrapArray: NameType = "genericWrapArray" // Compiler utilized names // val productElementName: NameType = "productElementName" - val TYPE_ : NameType = "TYPE" - val add_ : NameType = "add" - val anyValClass: NameType = "anyValClass" - val append: NameType = "append" - 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 formatted: NameType = "formatted" - 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 _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 macro_ : NameType = "macro" - val main: NameType = "main" - val map: NameType = "map" - val missingCase: NameType = "missingCase" - 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 productIterator: NameType = "productIterator" - val productPrefix: NameType = "productPrefix" - val readResolve: NameType = "readResolve" - val runOrElse: NameType = "runOrElse" - 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" + val Ident: NameType = "Ident" + val TYPE_ : NameType = "TYPE" + val TypeTree: NameType = "TypeTree" + val UNIT : NameType = "UNIT" + val _isDefinedAt: NameType = "_isDefinedAt" + val add_ : NameType = "add" + val annotation: NameType = "annotation" + val anyValClass: NameType = "anyValClass" + val append: NameType = "append" + val apply: NameType = "apply" + val applyDynamic: NameType = "applyDynamic" + val args : NameType = "args" + val argv : NameType = "argv" + val arrayValue: NameType = "arrayValue" + val array_apply : NameType = "array_apply" + val array_clone : NameType = "array_clone" + val array_length : NameType = "array_length" + val array_update : NameType = "array_update" + val arraycopy: NameType = "arraycopy" + val asInstanceOf_ : NameType = "asInstanceOf" + val asTypeConstructor: NameType = "asTypeConstructor" + 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 emptyValDef: NameType = "emptyValDef" + val ensureAccessible : NameType = "ensureAccessible" + val eq: NameType = "eq" + val equalsNumChar : NameType = "equalsNumChar" + val equalsNumNum : NameType = "equalsNumNum" + val equalsNumObject : NameType = "equalsNumObject" + 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 formatted: NameType = "formatted" + val freeValue : NameType = "freeValue" + val genericArrayOps: NameType = "genericArrayOps" + val get: NameType = "get" + val glob : NameType = "glob" + 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 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 macro_ : NameType = "macro" + val main: NameType = "main" + val map: NameType = "map" + val mirror : NameType = "mirror" + val missingCase: NameType = "missingCase" + val ne: NameType = "ne" + val newArray: NameType = "newArray" + val newScopeWith: NameType = "newScopeWith" + 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 productIterator: NameType = "productIterator" + val productPrefix: NameType = "productPrefix" + val readResolve: NameType = "readResolve" + val runOrElse: NameType = "runOrElse" + val runtime: NameType = "runtime" + val sameElements: NameType = "sameElements" + val scala_ : NameType = "scala" + val self: NameType = "self" + val setAccessible: NameType = "setAccessible" + val setAnnotations: NameType = "setAnnotations" + val setTypeSig: NameType = "setTypeSig" + val synchronized_ : NameType = "synchronized" + val tail: NameType = "tail" + val thisModuleType: NameType = "thisModuleType" + val this_ : NameType = "this" + val throw_ : NameType = "throw" + val toArray: NameType = "toArray" + val toList: NameType = "toList" + val toObjectArray : NameType = "toObjectArray" + val toSeq: NameType = "toSeq" + val toString_ : NameType = if (forMSIL) "ToString" else "toString" + val true_ : NameType = "true" + val typedProductIterator: NameType = "typedProductIterator" + val unapply: NameType = "unapply" + val unapplySeq: NameType = "unapplySeq" + val unbox: NameType = "unbox" + val update: NameType = "update" + val value: NameType = "value" + val valueOf : NameType = "valueOf" + val values : NameType = "values" + val view_ : NameType = "view" + val wait_ : NameType = "wait" + val withFilter: NameType = "withFilter" + val zip: NameType = "zip" // unencoded operators object raw { @@ -316,21 +391,53 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy val toLong: NameType = "toLong" val toFloat: NameType = "toFloat" val toDouble: NameType = "toDouble" + + // primitive operation methods for structual types mostly + // overlap with the above, but not for these two. + val toCharacter: NameType = "toCharacter" + val toInteger: NameType = "toInteger" } object tpnme extends TypeNames /*with LibraryTypeNames*/ with TypeNameMangling { type NameType = TypeName - implicit def createNameType(name: String): TypeName = newTypeName(name) + protected implicit def createNameType(name: String): TypeName = newTypeNameCached(name) val REFINE_CLASS_NAME: NameType = "<refinement>" val ANON_CLASS_NAME: NameType = "$anon" } + + /** For fully qualified type names. + */ + object fulltpnme extends TypeNames { + type NameType = TypeName + protected implicit def createNameType(name: String): TypeName = newTypeNameCached(name) + + val RuntimeNothing: NameType = "scala.runtime.Nothing$" + val RuntimeNull: NameType = "scala.runtime.Null$" + val JavaLangEnum: NameType = "java.lang.Enum" + } + + /** Java binary names, like scala/runtime/Nothing$. + */ + object binarynme { + def toBinary(name: Name) = name mapName (_.replace('.', '/')) + + val RuntimeNothing = toBinary(fulltpnme.RuntimeNothing).toTypeName + val RuntimeNull = toBinary(fulltpnme.RuntimeNull).toTypeName + } + + object fullnme extends TermNames { + type NameType = TermName + protected implicit def createNameType(name: String): TermName = newTermNameCached(name) + + val MirrorPackage: NameType = "scala.reflect.mirror" + } val javanme = nme.javaKeywords object nme extends TermNames /*with LibraryTermNames*/ with TermNameMangling { type NameType = TermName - def createNameType(name: String): TermName = newTermName(name) + protected implicit def createNameType(name: String): TermName = newTermNameCached(name) /** Translate a String into a list of simple TypeNames and TermNames. * In all segments before the last, type/term is determined by whether @@ -363,7 +470,7 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy 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)) + val (simple, div, rest) = (name take idx, name charAt idx, newTermName(name) drop (idx + 1)) mkName(simple, div == '.') :: segments(rest, assumeTerm) } } @@ -380,26 +487,27 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy /** 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) + newTermNameCached(base.fullName('$') + separator + name) - def moduleVarName(name: TermName): TermName = newTermName("" + name + MODULE_VAR_SUFFIX) - - val EXPAND_SEPARATOR_STRING = "$$" - val LOCAL_SUFFIX_STRING = " " + def moduleVarName(name: TermName): TermName = + newTermNameCached("" + name + MODULE_VAR_SUFFIX) + val ROOTPKG: TermName = "_root_" /** Base strings from which synthetic names are derived. */ - 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_VAR_PREFIX = "res" - val INTERPRETER_WRAPPER_SUFFIX = "$object" - val WHILE_PREFIX = "while$" + val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$" + val DEFAULT_GETTER_STRING = "$default$" + val DO_WHILE_PREFIX = "doWhile$" + val EQEQ_LOCAL_VAR_STRING = "eqEqTemp$" + val EVIDENCE_PARAM_PREFIX = "evidence$" + val EXCEPTION_RESULT_PREFIX = "exceptionResult" + val INTERPRETER_IMPORT_WRAPPER = "$iw" + val INTERPRETER_LINE_PREFIX = "line" + val INTERPRETER_VAR_PREFIX = "res" + val INTERPRETER_WRAPPER_SUFFIX = "$object" + val WHILE_PREFIX = "while$" + + val EQEQ_LOCAL_VAR: TermName = newTermName(EQEQ_LOCAL_VAR_STRING) def getCause = sn.GetCause def getClass_ = sn.GetClass @@ -424,8 +532,8 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy val MUL = encode("*") val NE = encode("!=") val OR = encode("|") - val PLUS = encode("+") - val SUB = encode("-") + val PLUS = ADD // technically redundant, but ADD looks funny with MINUS + val SUB = MINUS // ... as does SUB with PLUS val XOR = encode("^") val ZAND = encode("&&") val ZOR = encode("||") @@ -435,10 +543,138 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy val UNARY_+ = encode("unary_+") val UNARY_- = encode("unary_-") val UNARY_! = encode("unary_!") + + // Grouped here so Cleanup knows what tests to perform. + val CommonOpNames = Set[Name](OR, XOR, AND, EQ, NE) + val ConversionNames = Set[Name](toByte, toChar, toDouble, toFloat, toInt, toLong, toShort) + val BooleanOpNames = Set[Name](ZOR, ZAND, UNARY_!) ++ CommonOpNames + val NumberOpNames = ( + Set[Name](ADD, SUB, MUL, DIV, MOD, LSL, LSR, ASR, LT, LE, GE, GT) + ++ Set(UNARY_+, UNARY_-, UNARY_!) + ++ ConversionNames + ++ CommonOpNames + ) + + val add: NameType = "add" + val complement: NameType = "complement" + val divide: NameType = "divide" + val multiply: NameType = "multiply" + val negate: NameType = "negate" + val positive: NameType = "positive" + val shiftLogicalRight: NameType = "shiftLogicalRight" + val shiftSignedLeft: NameType = "shiftSignedLeft" + val shiftSignedRight: NameType = "shiftSignedRight" + val subtract: NameType = "subtract" + val takeAnd: NameType = "takeAnd" + val takeConditionalAnd: NameType = "takeConditionalAnd" + val takeConditionalOr: NameType = "takeConditionalOr" + val takeModulo: NameType = "takeModulo" + val takeNot: NameType = "takeNot" + val takeOr: NameType = "takeOr" + val takeXor: NameType = "takeXor" + val testEqual: NameType = "testEqual" + val testGreaterOrEqualThan: NameType = "testGreaterOrEqualThan" + val testGreaterThan: NameType = "testGreaterThan" + val testLessOrEqualThan: NameType = "testLessOrEqualThan" + val testLessThan: NameType = "testLessThan" + val testNotEqual: NameType = "testNotEqual" + + val isBoxedNumberOrBoolean: NameType = "isBoxedNumberOrBoolean" + val isBoxedNumber: NameType = "isBoxedNumber" + + def toUnaryName(name: TermName): TermName = name match { + case raw.MINUS => UNARY_- + case raw.PLUS => UNARY_+ + case raw.TILDE => UNARY_~ + case raw.BANG => UNARY_! + case _ => name + } + /** The name of a method which stands in for a primitive operation + * during structural type dispatch. + */ + def primitiveInfixMethodName(name: Name): TermName = name match { + case OR => takeOr + case XOR => takeXor + case AND => takeAnd + case EQ => testEqual + case NE => testNotEqual + case ADD => add + case SUB => subtract + case MUL => multiply + case DIV => divide + case MOD => takeModulo + case LSL => shiftSignedLeft + case LSR => shiftLogicalRight + case ASR => shiftSignedRight + case LT => testLessThan + case LE => testLessOrEqualThan + case GE => testGreaterOrEqualThan + case GT => testGreaterThan + case ZOR => takeConditionalOr + case ZAND => takeConditionalAnd + case _ => NO_NAME + } + /** Postfix/prefix, really. + */ + def primitivePostfixMethodName(name: Name): TermName = name match { + case UNARY_! => takeNot + case UNARY_+ => positive + case UNARY_- => negate + case UNARY_~ => complement + case `toByte` => toByte + case `toShort` => toShort + case `toChar` => toCharacter + case `toInt` => toInteger + case `toLong` => toLong + case `toFloat` => toFloat + case `toDouble` => toDouble + case _ => NO_NAME + } + + val reflPolyCacheName: NameType = "reflPoly$Cache" + val reflClassCacheName: NameType = "reflClass$Cache" + val reflParamsCacheName: NameType = "reflParams$Cache" + val reflMethodCacheName: NameType = "reflMethod$Cache" + val reflMethodName: NameType = "reflMethod$Method" + + private val reflectionCacheNames = Set[NameType]( + reflPolyCacheName, + reflClassCacheName, + reflParamsCacheName, + reflMethodCacheName, + reflMethodName + ) + def isReflectionCacheName(name: Name) = reflectionCacheNames exists (name startsWith _) + + @switch def productAccessorName(j: Int): TermName = j match { + case 1 => nme._1 + case 2 => nme._2 + case 3 => nme._3 + case 4 => nme._4 + case 5 => nme._5 + case 6 => nme._6 + case 7 => nme._7 + case 8 => nme._8 + case 9 => nme._9 + case 10 => nme._10 + case 11 => nme._11 + case 12 => nme._12 + case 13 => nme._13 + case 14 => nme._14 + case 15 => nme._15 + case 16 => nme._16 + case 17 => nme._17 + case 18 => nme._18 + case 19 => nme._19 + case 20 => nme._20 + case 21 => nme._21 + case 22 => nme._22 + case _ => newTermName("_" + j) + } } abstract class SymbolNames { - protected implicit def stringToTypeName(s: String): TypeName = newTypeName(s) + protected implicit def createNameType(s: String): TypeName = newTypeNameCached(s) val BeanProperty : TypeName val BooleanBeanProperty : TypeName @@ -471,7 +707,7 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy class JavaKeywords { private var kws: Set[TermName] = Set() private def kw(s: String): TermName = { - val result = newTermName(s) + val result = newTermNameCached(s) kws = kws + result result } @@ -555,12 +791,12 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy 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" + final val ForName: TermName = newTermName("forName") + final val GetCause: TermName = newTermName("getCause") + final val GetClass: TermName = newTermName("getClass") + final val GetMethod: TermName = newTermName("getMethod") + final val Invoke: TermName = newTermName("invoke") + final val JavaLang: TermName = newTermName("java.lang") val Boxed = immutable.Map[TypeName, TypeName]( tpnme.Boolean -> BoxedBoolean, @@ -593,12 +829,12 @@ trait StdNames extends /*reflect.generic.StdNames with*/ NameManglers { self: Sy 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" + final val ForName: TermName = newTermName("GetType") + final val GetCause: TermName = newTermName("InnerException") /* System.Reflection.TargetInvocationException.InnerException */ + final val GetClass: TermName = newTermName("GetType") + final val GetMethod: TermName = newTermName("GetMethod") + final val Invoke: TermName = newTermName("Invoke") + final val JavaLang: TermName = newTermName("System") val Boxed = immutable.Map[TypeName, TypeName]( tpnme.Boolean -> "System.Boolean", diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 0e9210f1f7..5be69e06ad 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -10,9 +10,11 @@ import scala.collection.{ mutable, immutable } import util._ abstract class SymbolTable extends api.Universe + with Collections with Names with Symbols with Types + with Kinds with Scopes with Definitions with Constants @@ -31,8 +33,8 @@ abstract class SymbolTable extends api.Universe { def rootLoader: LazyType def log(msg: => AnyRef): Unit - def abort(msg: String): Nothing = throw new Error(msg) - def abort(): Nothing = throw new Error() + def abort(msg: String): Nothing = throw new FatalError(msg) + def abort(): Nothing = abort("unknown error") /** Override with final implementation for inlining. */ def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg) diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index a59ea2c1bf..6ee061392c 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -264,7 +264,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Create a new getter for current symbol (which must be a field) */ final def newGetter: Symbol = ( - owner.newMethod(focusPos(pos), nme.getterName(name)) + owner.newMethod(focusPos(pos), nme.getterName(name.toTermName)) setFlag getterFlags(flags) setPrivateWithin privateWithin setInfo MethodType(Nil, tpe) @@ -409,7 +409,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => 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 isHigherOrderTypeParameter = (this ne NoSymbol) && 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 } @@ -430,7 +430,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isDefinedInPackage = effectiveOwner.isPackageClass final def isJavaInterface = isJavaDefined && isTrait - final def needsFlatClasses: Boolean = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass + final def needsFlatClasses = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass // In java.lang, Predef, or scala package/package object def isInDefaultNamespace = UnqualifiedOwners(effectiveOwner) @@ -494,8 +494,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => // string. So this needs attention. For now the fact that migration is // private[scala] ought to provide enough protection. def hasMigrationAnnotation = hasAnnotation(MigrationAnnotationClass) - def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(2) } - def migrationVersion = getAnnotation(MigrationAnnotationClass) map { version => version.intArg(0).get + "." + version.intArg(1).get } + def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(0) } + def migrationVersion = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(1) } def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) } def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) } @@ -699,16 +699,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => rawowner = owner } - private[Symbols] def flattenName(): Name = { - // This assertion caused me no end 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. Finally I gave up and disabled it, and tickets like - // SI-4874 instantly start working. - // 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 originalOwnerChain: List[Symbol] = this :: originalOwner.getOrElse(this, rawowner).originalOwnerChain @@ -756,7 +746,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** If this symbol has an expanded name, its original name, otherwise its name itself. * @see expandName */ - def originalName = nme.originalName(name) + def originalName: Name = nme.originalName(name) /** The name of the symbol before decoding, e.g. `\$eq\$eq` instead of `==`. */ @@ -764,20 +754,28 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** The decoded name of the symbol, e.g. `==` instead of `\$eq\$eq`. */ - def decodedName: String = stripNameString(NameTransformer.decode(encodedName)) + def decodedName: String = nme.dropLocalSuffix(name).decode - /** Either "$" or "" depending on whether this is a module class. - */ + private def addModuleSuffix(n: Name): Name = + if (needsModuleSuffix) n append nme.MODULE_SUFFIX_STRING else n + def moduleSuffix: String = ( - if (hasModuleFlag && !isMethod && !isImplClass && !isJavaDefined) nme.MODULE_SUFFIX_STRING + if (needsModuleSuffix) nme.MODULE_SUFFIX_STRING else "" ) - + /** Whether this symbol needs nme.MODULE_SUFFIX_STRING (aka $) appended on the java platform. + */ + def needsModuleSuffix = ( + hasModuleFlag + && !isMethod + && !isImplClass + && !isJavaDefined + ) /** These should be moved somewhere like JavaPlatform. */ - def javaSimpleName = ("" + simpleName).trim + moduleSuffix - def javaBinaryName = fullNameInternal('/') + moduleSuffix - def javaClassName = fullNameInternal('.') + moduleSuffix + def javaSimpleName: String = addModuleSuffix(nme.dropLocalSuffix(simpleName)).toString + def javaBinaryName: String = addModuleSuffix(fullNameInternal('/')).toString + def javaClassName: String = addModuleSuffix(fullNameInternal('.')).toString /** The encoded full path name of this symbol, where outer names and inner names * are separated by `separator` characters. @@ -785,22 +783,18 @@ trait Symbols extends api.Symbols { self: SymbolTable => * Never adds id. * Drops package objects. */ - final def fullName(separator: Char): String = stripNameString(fullNameInternal(separator)) + final def fullName(separator: Char): String = fullNameAsName(separator).toString /** Doesn't drop package objects, for those situations (e.g. classloading) * where the true path is needed. */ - private def fullNameInternal(separator: Char): String = ( - if (isRoot || isRootPackage || this == NoSymbol) this.toString - else if (owner.isEffectiveRoot) encodedName - else effectiveOwner.enclClass.fullName(separator) + separator + encodedName + private def fullNameInternal(separator: Char): Name = ( + if (isRoot || isRootPackage || this == NoSymbol) name + else if (owner.isEffectiveRoot) name + else effectiveOwner.enclClass.fullNameAsName(separator) append separator append name ) - - /** Strip package objects and any local suffix. - */ - private def stripNameString(s: String) = - if (settings.debug.value) s - else s stripSuffix nme.LOCAL_SUFFIX_STRING + + def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator)) /** The encoded full path name of this symbol, where outer names and inner names * are separated by periods. @@ -1097,6 +1091,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => def typeParams: List[Symbol] = if (isMonomorphicType) Nil else { + // analogously to the "info" getter, here we allow for two completions: + // one: sourceCompleter to LazyType, two: LazyType to completed type + if (validTo == NoPeriod) + atPhase(phaseOf(infos.validFrom))(rawInfo load this) if (validTo == NoPeriod) atPhase(phaseOf(infos.validFrom))(rawInfo load this) @@ -1238,12 +1236,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ 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 eq that) || this.isError || that.isError || - info.baseTypeIndex(that) >= 0 - ) + + /** Is this class symbol a subclass of that symbol, + * and is this class symbol also different from Null or Nothing? */ + def isNonBottomSubClass(that: Symbol): Boolean = false /** Overridden in NullClass and NothingClass for custom behavior. */ @@ -1365,7 +1361,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** The symbol accessed by this accessor function, but with given owner type. */ final def accessed(ownerTp: Type): Symbol = { assert(hasAccessorFlag, this) - ownerTp decl nme.getterToLocal(getterName) + ownerTp decl nme.getterToLocal(getterName.toTermName) } /** The module corresponding to this module class (note that this @@ -1698,17 +1694,17 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def getter(base: Symbol): Symbol = base.info.decl(getterName) filter (_.hasAccessorFlag) - def getterName = ( - if (isSetter) nme.setterToGetter(name) - else if (nme.isLocalName(name)) nme.localToGetter(name) - else name + def getterName: TermName = ( + if (isSetter) nme.setterToGetter(name.toTermName) + else if (nme.isLocalName(name)) nme.localToGetter(name.toTermName) + else name.toTermName ) /** 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)) + var sname = nme.getterToSetter(nme.getterName(name.toTermName)) if (hasExpandedName) sname = nme.expandedSetterName(sname, base) base.info.decl(sname) filter (_.hasAccessorFlag) } @@ -1763,7 +1759,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => getter(owner).expandName(base) setter(owner).expandName(base) } - name = nme.expandedName(name, base) + name = nme.expandedName(name.toTermName, base) if (isType) name = name } } @@ -1796,7 +1792,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => // ------ toString ------------------------------------------------------------------- /** A tag which (in the ideal case) uniquely identifies class symbols */ - final def tag = fullName.## + final def tag: Int = fullName.## /** The simple name of this Symbol */ final def simpleName: Name = name @@ -1806,7 +1802,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * (the initial Name) before falling back on id, which varies depending * on exactly when a symbol is loaded. */ - final def sealedSortName = initName + "#" + id + final def sealedSortName: String = initName + "#" + id /** String representation of symbol's definition key word */ final def keyString: String = @@ -1874,7 +1870,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => * E.g. $eq => =. * If settings.uniqid, adds id. */ - def nameString = decodedName + idString + def nameString: String = ( + if (settings.uniqid.value) decodedName + "#" + id + else "" + decodedName + ) /** If settings.uniqid is set, the symbol's id, else "" */ final def idString = if (settings.uniqid.value) "#"+id else "" @@ -1882,14 +1881,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** 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( + override def toString: String = compose( kindString, if (hasMeaninglessName) owner.decodedName + idString else nameString ) /** String representation of location. */ - def ownsString = { + def ownsString: String = { val owns = effectiveOwner if (owns.isClass && !owns.isEmptyPrefix) "" + owns else "" } @@ -1897,12 +1896,12 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** String representation of location, plus a preposition. Doesn't do much, * for backward compatibility reasons. */ - def locationString = ownsString match { + def locationString: String = ownsString match { case "" => "" case s => " in " + s } - def fullLocationString = toString + locationString - def signatureString = if (hasRawInfo) infoString(rawInfo) else "<_>" + def fullLocationString: String = toString + locationString + def signatureString: String = if (hasRawInfo) infoString(rawInfo) else "<_>" /** String representation of symbol's definition following its name */ final def infoString(tp: Type): String = { @@ -1994,7 +1993,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => extends Symbol(initOwner, initPos, initName) { final override def isTerm = true - override def name: TermName = super.name + override def name: TermName = rawname.toTermName privateWithin = NoSymbol var referenced: Symbol = NoSymbol @@ -2081,20 +2080,20 @@ trait Symbols extends api.Symbols { self: SymbolTable => 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 + override def owner = ( + if (!isMethod && needsFlatClasses) rawowner.owner else rawowner - - override def name: TermName = - if (isFlatAdjusted) { - if (flatname == null) - flatname = flattenName().toTermName - + ) + override def name: TermName = ( + if (!isMethod && needsFlatClasses) { + if (flatname eq null) + flatname = nme.flattenedName(rawowner.name, rawname) + flatname - } else rawname + } + else rawname.toTermName + ) override def cloneSymbolImpl(owner: Symbol): Symbol = new ModuleSymbol(owner, pos, name).copyAttrsFrom(this) @@ -2217,6 +2216,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => super.info_=(tp) } + final override def isNonBottomSubClass(that: Symbol): Boolean = ( + (this eq that) || this.isError || that.isError || + info.baseTypeIndex(that) >= 0 + ) + override def reset(completer: Type) { super.reset(completer) tpePeriod = NoPeriod @@ -2288,7 +2292,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** A class for class symbols */ class ClassSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) extends TypeSymbol(initOwner, initPos, initName) { - + private var flatname: TypeName = null private var source: AbstractFileType = null private var thissym: Symbol = this @@ -2307,20 +2311,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => 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 @@ -2336,7 +2326,19 @@ trait Symbols extends api.Symbols { self: SymbolTable => } thisTypeCache } - + + override def owner: Symbol = + if (needsFlatClasses) rawowner.owner else rawowner + override def name: TypeName = ( + if (needsFlatClasses) { + if (flatname eq null) + flatname = nme.flattenedName(rawowner.name, rawname).toTypeName + + flatname + } + else rawname.toTypeName + ) + /** A symbol carrying the self type of the class as its type */ override def thisSym: Symbol = thissym @@ -2407,7 +2409,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def sourceModule_=(module: Symbol) { this.module = module } } - class FreeVar(name: TermName, tpe: Type, val value: Any) extends TermSymbol(definitions.RootClass, NoPosition, name) { + class FreeVar(name0: TermName, tpe: Type, val value: Any) extends TermSymbol(definitions.RootClass, NoPosition, name0) { setInfo(tpe) override def hashCode = value.hashCode @@ -2511,6 +2513,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => val syms1 = cloneSymbolsAtOwner(syms, owner) creator(syms1, tpe.substSym(syms, syms1)) } + + /** A deep map on a symbol's paramss. + */ + def mapParamss[T](sym: Symbol)(f: Symbol => T): List[List[T]] = mmap(sym.info.paramss)(f) /** Create a new existential type skolem with the given owner and origin. */ diff --git a/src/compiler/scala/reflect/internal/TreeGen.scala b/src/compiler/scala/reflect/internal/TreeGen.scala index 1c93a904c0..e537c6b83f 100644 --- a/src/compiler/scala/reflect/internal/TreeGen.scala +++ b/src/compiler/scala/reflect/internal/TreeGen.scala @@ -154,9 +154,13 @@ abstract class TreeGen { debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase) assert(!tree.tpe.isInstanceOf[MethodType], tree) assert(!pt.typeSymbol.isPackageClass && !pt.typeSymbol.isPackageObjectClass, pt) - // @MAT only called during erasure, which already takes care of that - // @PP: "only called during erasure" is not very true these days. - // In addition, at least, are: typer, uncurry, explicitouter, cleanup. + // called during (at least): typer, uncurry, explicitouter, cleanup. + // TODO: figure out the truth table for any/wrapInApply + // - the `any` flag seems to relate to erasure's adaptMember: "x.asInstanceOf[T] becomes x.$asInstanceOf[T]", + // where asInstanceOf is Any_asInstanceOf and $asInstanceOf is Object_asInstanceOf + // erasure will only unbox the value in a tree made by mkCast if `any && wrapInApply` + // - the `wrapInApply` flag need not be true if the tree will be adapted to have the empty argument list added before it gets to erasure + // in fact, I think it should be false for trees that will be type checked during typer assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize)) atPos(tree.pos)(mkAsInstanceOf(tree, pt, any = false, wrapInApply = true)) } @@ -262,6 +266,25 @@ abstract class TreeGen { tree setType tp } + def mkZeroContravariantAfterTyper(tp: Type): Tree = { + // contravariant -- for replacing an argument in a method call + // must use subtyping, as otherwise we miss types like `Any with Int` + val tree = + if (NullClass.tpe <:< tp) Literal(Constant(null)) + else if (UnitClass.tpe <:< tp) Literal(Constant()) + else if (BooleanClass.tpe <:< tp) Literal(Constant(false)) + else if (FloatClass.tpe <:< tp) Literal(Constant(0.0f)) + else if (DoubleClass.tpe <:< tp) Literal(Constant(0.0d)) + else if (ByteClass.tpe <:< tp) Literal(Constant(0.toByte)) + else if (ShortClass.tpe <:< tp) Literal(Constant(0.toShort)) + else if (IntClass.tpe <:< tp) Literal(Constant(0)) + else if (LongClass.tpe <:< tp) Literal(Constant(0L)) + else if (CharClass.tpe <:< tp) Literal(Constant(0.toChar)) + else mkCast(Literal(Constant(null)), tp) + + tree + } + /** Builds a tuple */ def mkTuple(elems: List[Tree]): Tree = if (elems.isEmpty) Literal(Constant()) diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index 1dc93a7add..e3ee39d2a0 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -107,7 +107,15 @@ abstract class TreeInfo { @deprecated("Use isExprSafeToInline instead", "2.10.0") def isPureExpr(tree: Tree) = isExprSafeToInline(tree) - def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] = { + def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] = + mapMethodParamsAndArgs(params, args)((param, arg) => ((param, arg))) + + def mapMethodParamsAndArgs[R](params: List[Symbol], args: List[Tree])(f: (Symbol, Tree) => R): List[R] = { + val b = List.newBuilder[R] + foreachMethodParamAndArg(params, args)((param, arg) => b += f(param, arg)) + b.result + } + def foreachMethodParamAndArg(params: List[Symbol], args: List[Tree])(f: (Symbol, Tree) => Unit): Boolean = { val plen = params.length val alen = args.length def fail() = { @@ -116,27 +124,29 @@ abstract class TreeInfo { " params = " + params + "\n" + " args = " + args + "\n" ) - params zip args + false } - if (plen == alen) params zip args - else if (params.isEmpty) fail + if (plen == alen) foreach2(params, args)(f) + else if (params.isEmpty) return fail else if (isVarArgsList(params)) { val plenInit = plen - 1 if (alen == plenInit) { if (alen == 0) Nil // avoid calling mismatched zip - else params.init zip args + else foreach2(params.init, args)(f) } - else if (alen < plenInit) fail + else if (alen < plenInit) return fail else { - val front = params.init zip (args take plenInit) - val back = args drop plenInit map (a => (params.last, a)) - front ++ back + foreach2(params.init, args take plenInit)(f) + val remainingArgs = args drop plenInit + foreach2(List.fill(remainingArgs.size)(params.last), remainingArgs)(f) } } - else fail - } + else return fail + true + } + /** * Selects the correct parameter list when there are nested applications. * Given Apply(fn, args), args might correspond to any of fn.symbol's parameter @@ -144,22 +154,28 @@ abstract class TreeInfo { * applies: for instance Apply(fn @ Apply(Apply(_, _), _), args) implies args * correspond to the third parameter list. * + * The argument fn is the function part of the apply node being considered. + * * Also accounts for varargs. */ + private def applyMethodParameters(fn: Tree): List[Symbol] = { + val depth = applyDepth(fn) + // There could be applies which go beyond the parameter list(s), + // being applied to the result of the method call. + // !!! Note that this still doesn't seem correct, although it should + // be closer than what it replaced. + if (depth < fn.symbol.paramss.size) fn.symbol.paramss(depth) + else if (fn.symbol.paramss.isEmpty) Nil + else fn.symbol.paramss.last + } + def zipMethodParamsAndArgs(t: Tree): List[(Symbol, Tree)] = t match { - case Apply(fn, args) => - val depth = applyDepth(fn) - // There could be applies which go beyond the parameter list(s), - // being applied to the result of the method call. - // !!! Note that this still doesn't seem correct, although it should - // be closer than what it replaced. - val params = ( - if (depth < fn.symbol.paramss.size) fn.symbol.paramss(depth) - else if (fn.symbol.paramss.isEmpty) Nil - else fn.symbol.paramss.last - ) - zipMethodParamsAndArgs(params, args) - case _ => Nil + case Apply(fn, args) => zipMethodParamsAndArgs(applyMethodParameters(fn), args) + case _ => Nil + } + def foreachMethodParamAndArg(t: Tree)(f: (Symbol, Tree) => Unit): Unit = t match { + case Apply(fn, args) => foreachMethodParamAndArg(applyMethodParameters(fn), args)(f) + case _ => } /** Is symbol potentially a getter of a variable? @@ -176,7 +192,7 @@ abstract class TreeInfo { def isVariableOrGetter(tree: Tree) = { def sym = tree.symbol def isVar = sym.isVariable - def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(nme.getterToSetter(sym.name)) != NoSymbol + def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(nme.getterToSetter(sym.name.toTermName)) != NoSymbol tree match { case Ident(_) => isVar diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 566ee0e9cf..96f2c5cc45 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -160,12 +160,12 @@ trait Trees extends api.Trees { self: SymbolTable => */ def ModuleDef(sym: Symbol, impl: Template): ModuleDef = atPos(sym.pos) { - ModuleDef(Modifiers(sym.flags), sym.name, impl) setSymbol sym + ModuleDef(Modifiers(sym.flags), sym.name.toTermName, impl) setSymbol sym } def ValDef(sym: Symbol, rhs: Tree): ValDef = atPos(sym.pos) { - ValDef(Modifiers(sym.flags), sym.name, + ValDef(Modifiers(sym.flags), sym.name.toTermName, TypeTree(sym.tpe) setPos focusPos(sym.pos), rhs) setSymbol sym } @@ -182,7 +182,7 @@ trait Trees extends api.Trees { self: SymbolTable => atPos(sym.pos) { assert(sym != NoSymbol) DefDef(Modifiers(sym.flags), - sym.name, + sym.name.toTermName, sym.typeParams map TypeDef, vparamss, TypeTree(sym.tpe.finalResultType) setPos focusPos(sym.pos), @@ -193,7 +193,7 @@ trait Trees extends api.Trees { self: SymbolTable => 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) + DefDef(sym, mods, mapParamss(sym)(ValDef), rhs) def DefDef(sym: Symbol, rhs: Tree): DefDef = DefDef(sym, Modifiers(sym.flags), rhs) @@ -214,7 +214,7 @@ trait Trees extends api.Trees { self: SymbolTable => def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef = atPos(sym.pos) { - LabelDef(sym.name, params map Ident, rhs) setSymbol sym + LabelDef(sym.name.toTermName, params map Ident, rhs) setSymbol sym } @@ -248,10 +248,13 @@ trait Trees extends api.Trees { self: SymbolTable => /** 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) + def Block(stats: Tree*): Block = { + if (stats.isEmpty) Block(Nil, Literal(Constant(()))) + else stats match { + case Seq(b @ Block(_, _)) => b + case Seq(stat) => Block(stats.toList, Literal(Constant(()))) + case Seq(_, rest @ _*) => Block(stats.init.toList, stats.last) + } } // --- specific traversers and transformers diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 265261f594..4630733db4 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -87,11 +87,20 @@ trait Types extends api.Types { self: SymbolTable => private final def decr(depth: Int) = if (depth == AnyDepth) AnyDepth else depth - 1 private final val printLubs = sys.props contains "scalac.debug.lub" + private final val traceTypeVars = sys.props contains "scalac.debug.tvar" /** In case anyone wants to turn off lub verification without reverting anything. */ private final val verifyLubs = true + /** In case anyone wants to turn off type parameter bounds being used + * to seed type constraints. + */ + private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints" protected val enableTypeVarExperimentals = settings.Xexperimental.value + /** Empty immutable maps to avoid allocations. */ + private val emptySymMap = immutable.Map[Symbol, Symbol]() + private val emptySymCount = immutable.Map[Symbol, Int]() + /** The current skolemization level, needed for the algorithms * in isSameType, isSubType that do constraint solving under a prefix. */ @@ -484,7 +493,6 @@ trait Types extends api.Types { self: SymbolTable => /** 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. @@ -496,6 +504,9 @@ trait Types extends api.Types { self: SymbolTable => * Alternatives of overloaded symbol appear in the order they are declared. */ def decl(name: Name): Symbol = findDecl(name, 0) + + /** A list of all non-private members defined or declared in this type. */ + def nonPrivateDecls: List[Symbol] = decls filter (x => !x.isPrivate) toList /** The non-private defined or declared members with name `name` in this type; * an OverloadedSymbol if several exist, NoSymbol if none exist. @@ -507,47 +518,67 @@ trait Types extends api.Types { self: SymbolTable => * 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 + def members: List[Symbol] = membersBasedOnFlags(0, 0) /** A list of all non-private members of this type (defined or inherited) */ - def nonPrivateMembers: List[Symbol] = - findMember(nme.ANYNAME, PRIVATE | BridgeFlags, 0, false).alternatives + def nonPrivateMembers: List[Symbol] = membersBasedOnFlags(BridgeAndPrivateFlags, 0) /** 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 | BridgeFlags) & ~admit, 0, false).alternatives + def nonPrivateMembersAdmitting(admit: Long): List[Symbol] = membersBasedOnFlags(BridgeAndPrivateFlags & ~admit, 0) /** A list of all implicit symbols of this type (defined or inherited) */ - def implicitMembers: List[Symbol] = - findMember(nme.ANYNAME, BridgeFlags, IMPLICIT, false).alternatives + def implicitMembers: List[Symbol] = membersBasedOnFlags(BridgeFlags, IMPLICIT) /** A list of all deferred symbols of this type (defined or inherited) */ - def deferredMembers: List[Symbol] = - findMember(nme.ANYNAME, BridgeFlags, DEFERRED, false).alternatives + def deferredMembers: List[Symbol] = membersBasedOnFlags(BridgeFlags, DEFERRED) /** The member with given name, * an OverloadedSymbol if several exist, NoSymbol if none exist */ - def member(name: Name): Symbol = findMember(name, BridgeFlags, 0, false) + def member(name: Name): Symbol = + memberBasedOnName(name, BridgeFlags) /** 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 | BridgeFlags, 0, false) + memberBasedOnName(name, BridgeAndPrivateFlags) + + /** All members with the given flags, excluding bridges. + */ + def membersWithFlags(requiredFlags: Long): List[Symbol] = + membersBasedOnFlags(BridgeFlags, requiredFlags) - /** The non-private member with given name, admitting members with given flags `admit` - * an OverloadedSymbol if several exist, NoSymbol if none exist + /** All non-private members with the given flags, excluding bridges. + */ + def nonPrivateMembersWithFlags(requiredFlags: Long): List[Symbol] = + membersBasedOnFlags(BridgeAndPrivateFlags, requiredFlags) + + /** The non-private member with given name, admitting members with given flags `admit`. + * "Admitting" refers to the fact that members with a PRIVATE, BRIDGE, or VBRIDGE + * flag are usually excluded from findMember results, but supplying any of those flags + * to this method disables that exclusion. + * + * An OverloadedSymbol if several exist, NoSymbol if none exists. */ def nonPrivateMemberAdmitting(name: Name, admit: Long): Symbol = - findMember(name, (PRIVATE | BridgeFlags) & ~admit, 0, false) + memberBasedOnName(name, BridgeAndPrivateFlags & ~admit) /** The non-local member with given name, * an OverloadedSymbol if several exist, NoSymbol if none exist */ def nonLocalMember(name: Name): Symbol = - findMember(name, LOCAL | BridgeFlags, 0, false) + memberBasedOnName(name, BridgeFlags | LOCAL) + + /** Members excluding and requiring the given flags. + * Note: unfortunately it doesn't work to exclude DEFERRED this way. + */ + def membersBasedOnFlags(excludedFlags: Long, requiredFlags: Long): List[Symbol] = + findMember(nme.ANYNAME, excludedFlags, requiredFlags, false).alternatives + + def memberBasedOnName(name: Name, excludedFlags: Long): Symbol = + findMember(name, excludedFlags, 0, false) /** The least type instance of given class which is a supertype * of this type. Example: @@ -568,7 +599,7 @@ trait Types extends api.Types { self: SymbolTable => * T.asSeenFrom(ThisType(C), D) (where D is owner of m) * = Int */ - def asSeenFrom(pre: Type, clazz: Symbol): Type = + def asSeenFrom(pre: Type, clazz: Symbol): Type = { if (isTrivial || phase.erasedTypes && pre.typeSymbol != ArrayClass) this else { // scala.tools.nsc.util.trace.when(pre.isInstanceOf[ExistentialType])("X "+this+".asSeenfrom("+pre+","+clazz+" = ") { @@ -584,6 +615,7 @@ trait Types extends api.Types { self: SymbolTable => stopTimer(asSeenFromNanos, start) result } + } /** The info of `sym`, seen as a member of this type. * @@ -649,7 +681,11 @@ trait Types extends api.Types { self: SymbolTable => } /** Returns all parts of this type which satisfy predicate `p` */ - def filter(p: Type => Boolean): List[Type] = new FilterTypeCollector(p).collect(this).toList + def filter(p: Type => Boolean): List[Type] = new FilterTypeCollector(p) collect this + def withFilter(p: Type => Boolean) = new FilterTypeCollector(p) { + def foreach[U](f: Type => U): Unit = collect(Type.this) foreach f + def map[T](f: Type => T): List[T] = collect(Type.this) map f + } /** Returns optionally first type (in a preorder traversal) which satisfies predicate `p`, * or None if none exists. @@ -1002,7 +1038,6 @@ trait Types extends api.Types { self: SymbolTable => 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() @@ -1283,6 +1318,7 @@ trait Types extends api.Types { self: SymbolTable => case TypeBounds(_, _) => that <:< this case _ => lo <:< that && that <:< hi } + def isEmptyBounds = (lo.typeSymbolDirect eq NothingClass) && (hi.typeSymbolDirect eq AnyClass) // override def isNullable: Boolean = NullClass.tpe <:< lo; override def safeToString = ">: " + lo + " <: " + hi override def kind = "TypeBoundsType" @@ -1609,29 +1645,40 @@ trait Types extends api.Types { self: SymbolTable => // (this can happen only for erroneous programs). } + private object enterRefs extends TypeMap { + private var tparam: Symbol = _ + + def apply(tp: Type): Type = { + tp match { + case TypeRef(_, sym, args) if args.nonEmpty => + if (settings.debug.value && !sameLength(sym.info.typeParams, args)) + debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + args) + + foreach2(sym.info.typeParams, args) { (tparam1, arg) => + if (arg contains tparam) { + addRef(NonExpansive, tparam, tparam1) + if (arg.typeSymbol != tparam) + addRef(Expansive, tparam, tparam1) + } + } + case _ => + } + mapOver(tp) + } + def enter(tparam0: Symbol, parent: Type) { + this.tparam = tparam0 + this(parent) + } + } + /** 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) if args.nonEmpty => - if (settings.debug.value && !sameLength(sym.info.typeParams, args)) - debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + 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) - } + typeSymbol.typeParams foreach { tparam => + parents foreach { p => + enterRefs.enter(tparam, p) } - for (p <- parents) enterRefs(p) } state = Initializing } @@ -1896,7 +1943,7 @@ A type's typeSymbol should never be inspected directly. // note: does not go through typeRef. There's no need to because // neither `pre` nor `sym` changes. And there's a performance // advantage to call TypeRef directly. - override def typeConstructor = TypeRef(pre, sym, Nil) + override def typeConstructor = if (args.isEmpty) this else TypeRef(pre, sym, Nil) // A reference (in a Scala program) to a type that has type // parameters, but where the reference does not include type @@ -2149,15 +2196,23 @@ A type's typeSymbol should never be inspected directly. override def isJava = true } - case class NullaryMethodType(override val resultType: Type) extends SimpleTypeProxy { - override def underlying = resultType - override def isTrivial = resultType.isTrivial && (resultType eq resultType.withoutAnnotations) - override def paramSectionCount = 0 - override def paramss = Nil - override def params = Nil - override def paramTypes = Nil - override def safeToString = "=> " + resultType - override def kind = "NullaryMethodType" + case class NullaryMethodType(override val resultType: Type) extends Type { + override def isTrivial = resultType.isTrivial && (resultType eq resultType.withoutAnnotations) + 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 @@ -2224,6 +2279,15 @@ A type's typeSymbol should never be inspected directly. } object PolyType extends PolyTypeExtractor + + /** A creator for existential types which flattens nested existentials. + */ + def newExistentialType(quantified: List[Symbol], underlying: Type): Type = + if (quantified.isEmpty) underlying + else underlying match { + case ExistentialType(qs, restpe) => newExistentialType(quantified ::: qs, restpe) + case _ => ExistentialType(quantified, underlying) + } case class ExistentialType(quantified: List[Symbol], override val underlying: Type) extends RewrappingTypeProxy @@ -2288,7 +2352,7 @@ A type's typeSymbol should never be inspected directly. } override def cloneInfo(owner: Symbol) = - createFromClonedSymbolsAtOwner(quantified, owner, underlying)(ExistentialType(_, _)) + createFromClonedSymbolsAtOwner(quantified, owner, underlying)(newExistentialType) override def atOwner(owner: Symbol) = if (quantified exists (_.owner != owner)) cloneInfo(owner) else this @@ -2373,31 +2437,54 @@ A type's typeSymbol should never be inspected directly. // 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 + @inline final def trace[T](action: String, msg: => String)(value: T): T = { + if (traceTypeVars) { + val s = msg match { + case "" => "" + case str => "( " + str + " )" } - suspended.clear() + Console.err.println("[%10s] %-25s%s".format(action, value, s)) } + value + } + + /** Create a new TypeConstraint based on the given symbol. + */ + private def deriveConstraint(tparam: Symbol): TypeConstraint = { + /** Must force the type parameter's info at this point + * or things don't end well for higher-order type params. + * See SI-5359. + */ + val bounds = tparam.info.bounds + /** We can seed the type constraint with the type parameter + * bounds as long as the types are concrete. This should lower + * the complexity of the search even if it doesn't improve + * any results. + */ + if (propagateParameterBoundsToTypeVars) { + val exclude = bounds.isEmptyBounds || bounds.exists(_.typeSymbolDirect.isNonClassType) + + if (exclude) new TypeConstraint + else TypeVar.trace("constraint", "For " + tparam.fullLocationString)(new TypeConstraint(bounds)) + } + else new TypeConstraint + } + def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr)) + def apply(origin: Type, constr: TypeConstraint): TypeVar = apply(origin, constr, Nil, Nil) + def apply(tparam: Symbol): TypeVar = apply(tparam.tpeHK, deriveConstraint(tparam), Nil, tparam.typeParams) + + /** This is the only place TypeVars should be instantiated. + */ + def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]): TypeVar = { + val tv = ( + if (args.isEmpty && params.isEmpty) new TypeVar(origin, constr) + else if (args.size == params.size) new AppliedTypeVar(origin, constr, params zip args) + else if (args.isEmpty) new HKTypeVar(origin, constr, params) + else throw new TypeError("Invalid TypeVar construction: " + ((origin, constr, args, params))) + ) + + trace("create", "In " + tv.originLocation)(tv) } -*/ - def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr)) - def apply(origin: Type, constr: TypeConstraint) = new TypeVar(origin, constr, List(), List()) - // TODO why not initialise TypeConstraint with bounds of tparam? - // @PP: I tried that, didn't work out so well for me. - def apply(tparam: Symbol) = new TypeVar(tparam.tpeHK, new TypeConstraint, List(), tparam.typeParams) - def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]) = - new TypeVar(origin, constr, args, params) } // TODO: I don't really know why this happens -- maybe because @@ -2424,23 +2511,53 @@ A type's typeSymbol should never be inspected directly. tp.typeSymbol ) + /** Precondition: params.nonEmpty. (args.nonEmpty enforced structurally.) + */ + class HKTypeVar( + _origin: Type, + _constr: TypeConstraint, + override val params: List[Symbol] + ) extends TypeVar(_origin, _constr) { + + require(params.nonEmpty, this) + override def isHigherKinded = true + override protected def typeVarString = params.map(_.name).mkString("[", ", ", "]=>" + originName) + } + + /** Precondition: zipped params/args nonEmpty. (Size equivalence enforced structurally.) + */ + class AppliedTypeVar( + _origin: Type, + _constr: TypeConstraint, + zippedArgs: List[(Symbol, Type)] + ) extends TypeVar(_origin, _constr) { + + require(zippedArgs.nonEmpty, this) + + override def params: List[Symbol] = zippedArgs map (_._1) + override def typeArgs: List[Type] = zippedArgs map (_._2) + + override protected def typeVarString = ( + zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]") + ) + } + /** A class representing a type variable: not used after phase `typer`. * * A higher-kinded TypeVar has params (Symbols) and typeArgs (Types). * A TypeVar with nonEmpty typeArgs can only be instantiated by a higher-kinded * type that can be applied to those args. A TypeVar is much like a TypeRef, * except it has special logic for equality and subtyping. + * + * Precondition for this class, enforced structurally: args.isEmpty && params.isEmpty. */ class TypeVar( val origin: Type, - val constr0: TypeConstraint, - override val typeArgs: List[Type], - override val params: List[Symbol] + val constr0: TypeConstraint ) extends Type { - private val numArgs = typeArgs.length - // params are needed to keep track of variance (see mapOverArgs in SubstMap) - assert(typeArgs.isEmpty || sameLength(typeArgs, params)) - // var tid = { tidCount += 1; tidCount } //DEBUG + override def params: List[Symbol] = Nil + override def typeArgs: List[Type] = Nil + override def isHigherKinded = false /** The constraint associated with the variable */ var constr = constr0 @@ -2448,7 +2565,38 @@ A type's typeSymbol should never be inspected directly. /** 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 && typeArgs.isEmpty) + this + else if (newArgs.size == params.size) { + val tv = TypeVar(origin, constr, newArgs, params) + TypeVar.trace("applyArgs", "In " + originLocation + ", apply args " + newArgs.mkString(", ") + " to " + originName)(tv) + } + else + throw new TypeError("Invalid type application in TypeVar: " + params + ", " + newArgs) + ) + // newArgs.length may differ from args.length (could've been empty before) + // + // !!! @PP - I need an example of this, since this exception never triggers + // even though I am requiring the size match. + // + // 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 + // When comparing to types containing skolems, remember the highest level // of skolemization. If that highest level is higher than our initial // skolemizationLevel, we can't re-use those skolems as the solution of this @@ -2459,26 +2607,6 @@ A type's typeSymbol should never be inspected directly. private var encounteredHigherLevel = false private def shouldRepackType = enableTypeVarExperimentals && encounteredHigherLevel - /** 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) @@ -2487,7 +2615,8 @@ A type's typeSymbol should never be inspected directly. undoLog record this // if we were compared against later typeskolems, repack the existential, // because skolems are only compatible if they were created at the same level - constr.inst = if (shouldRepackType) repackExistential(tp) else tp + val res = if (shouldRepackType) repackExistential(tp) else tp + constr.inst = TypeVar.trace("setInst", "In " + originLocation + ", " + originName + "=" + res)(res) } def addLoBound(tp: Type, isNumericBound: Boolean = false) { @@ -2564,11 +2693,10 @@ A type's typeSymbol should never be inspected directly. * type parameter we're trying to infer (the result will be sanity-checked later). */ def unifyFull(tpe: Type) = { - // Since the alias/widen variations are often no-ops, this - // keenly collects them in a Set to avoid redundant tests. + // The alias/widen variations are often no-ops. val tpes = ( - if (isLowerBound) Set(tpe, tpe.widen, tpe.dealias, tpe.widen.dealias) - else Set(tpe) + if (isLowerBound) List(tpe, tpe.widen, tpe.dealias, tpe.widen.dealias).distinct + else List(tpe) ) tpes exists { tp => val lhs = if (isLowerBound) tp.typeArgs else typeArgs @@ -2668,32 +2796,56 @@ A type's typeSymbol should never be inspected directly. || !containsSkolemAboveLevel(tp) // side-effects tracking boolean || enableTypeVarExperimentals // -Xexperimental: always say we're relatable, track consequences ) - override val isHigherKinded = typeArgs.isEmpty && params.nonEmpty - override def normalize: Type = + 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 + private def tparamsOfSym(sym: Symbol) = sym.info match { + case PolyType(tparams, _) if tparams.nonEmpty => + tparams map (_.defString) mkString("[", ",", "]") + case _ => "" + } + def originName = { + val name = origin.typeSymbolDirect.decodedName + if (name contains "_$") origin.typeSymbolDirect.decodedName else name + } + def originLocation = { + val sym = origin.typeSymbolDirect + val encl = sym.owner.logicallyEnclosingMember + + // This should display somewhere between one and three + // things which enclose the origin: at most, a class, a + // a method, and a term. At least, a class. + List( + Some(encl.enclClass), + if (encl.isMethod) Some(encl) else None, + if (sym.owner.isTerm && (sym.owner != encl)) Some(sym.owner) else None + ).flatten map (s => s.decodedName + tparamsOfSym(s)) mkString "#" } + private def levelString = if (settings.explaintypes.value) level else "" + protected def typeVarString = originName + override def safeToString = ( + if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>" + else if (constr.inst ne NoType) "" + constr.inst + else "?" + levelString + originName + ) 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? + assert(!suspended, this) + TypeVar.trace("clone", originLocation)( + TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params? + ) } } @@ -2950,6 +3102,9 @@ A type's typeSymbol should never be inspected directly. /** A creator for intersection type where intersections of a single type are * replaced by the type itself, and repeated parent classes are merged. + * + * !!! Repeated parent classes are not merged - is this a bug in the + * comment or in the code? */ def intersectionType(tps: List[Type], owner: Symbol): Type = tps match { case List(tp) => @@ -2987,7 +3142,7 @@ A type's typeSymbol should never be inspected directly. case TypeRef(pre, sym @ (NothingClass|AnyClass), _) => copyTypeRef(tycon, pre, sym, Nil) //@M drop type args to Any/Nothing case TypeRef(pre, sym, _) => copyTypeRef(tycon, pre, sym, args) case PolyType(tparams, restpe) => restpe.instantiateTypeParams(tparams, args) - case ExistentialType(tparams, restpe) => ExistentialType(tparams, appliedType(restpe, args)) + case ExistentialType(tparams, restpe) => newExistentialType(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)) @@ -3026,71 +3181,23 @@ A type's typeSymbol should never be inspected directly. * * 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`. + * 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.isBottomClass && 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) - } - - // 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. - override def mapOver(tree: Tree) = tree match { - case Ident(_) if tree.tpe.isStable => tree - case _ => super.mapOver(tree) - } - } - val tpe1 = extrapolate(tpe) + val tpe = deAlias(tpe0) + val tpe1 = new ExistentialExtrapolation(tparams) extrapolate tpe var tparams0 = tparams var tparams1 = tparams0 filter tpe1.contains @@ -3100,11 +3207,7 @@ A type's typeSymbol should never be inspected directly. 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) - } + newExistentialType(tparams1, tpe1) } /** Remove any occurrences of type aliases from this type */ @@ -3196,7 +3299,7 @@ A type's typeSymbol should never be inspected directly. val isType = pnames.head.isTypeName val newParams = for (name <- pnames) yield if (isType) owner.newTypeParameter(NoPosition, name.toTypeName) - else owner.newValueParameter(NoPosition, name) + else owner.newValueParameter(NoPosition, name.toTermName) paramStack = newParams :: paramStack try { (newParams, ptypes).zipped foreach ((p, t) => p setInfo this(t)) @@ -3239,10 +3342,15 @@ A type's typeSymbol should never be inspected directly. */ class TypeConstraint(lo0: List[Type], hi0: List[Type], numlo0: Type, numhi0: Type, avoidWidening0: Boolean = false) { def this(lo0: List[Type], hi0: List[Type]) = this(lo0, hi0, NoType, NoType) + def this(bounds: TypeBounds) = this(List(bounds.lo), List(bounds.hi)) def this() = this(List(), List()) - private var lobounds = lo0 - private var hibounds = hi0 + /** Guard these lists against AnyClass and NothingClass appearing, + * else loBounds.isEmpty will have different results for an empty + * constraint and one with Nothing as a lower bound. + */ + private var lobounds = lo0 filterNot (_.typeSymbolDirect eq NothingClass) + private var hibounds = hi0 filterNot (_.typeSymbolDirect eq AnyClass) private var numlo = numlo0 private var numhi = numhi0 private var avoidWidening = avoidWidening0 @@ -3258,7 +3366,8 @@ A type's typeSymbol should never be inspected directly. else if (!isNumericSubType(tp, numlo)) numlo = numericLoBound } - else lobounds ::= tp + else if (tp.typeSymbolDirect ne NothingClass) + lobounds ::= tp } def checkWidening(tp: Type) { @@ -3277,7 +3386,8 @@ A type's typeSymbol should never be inspected directly. else if (!isNumericSubType(numhi, tp)) numhi = numericHiBound } - else hibounds ::= tp + else if (tp.typeSymbolDirect ne AnyClass) + hibounds ::= tp } def isWithinBounds(tp: Type): Boolean = @@ -3296,10 +3406,18 @@ A type's typeSymbol should never be inspected directly. tc } - override def toString = - (loBounds map (_.safeToString)).mkString("[ _>:(", ",", ") ") + - (hiBounds map (_.safeToString)).mkString("| _<:(", ",", ") ] _= ") + - inst.safeToString + override def toString = { + val boundsStr = ( + if (loBounds.isEmpty && hiBounds.isEmpty) "[]" + else { + val lostr = if (loBounds.isEmpty) "" else loBounds map (_.safeToString) mkString("_>:(", ", ", ")") + val histr = if (hiBounds.isEmpty) "" else hiBounds map (_.safeToString) mkString("_<:(", ", ", ")") + List(lostr, histr) filterNot (_ == "") mkString ("[", " | ", "]") + } + ) + if (inst eq NoType) boundsStr + else boundsStr + " _= " + inst.safeToString + } } trait AnnotationFilter extends TypeMap { @@ -3315,16 +3433,82 @@ A type's typeSymbol should never be inspected directly. def keepAnnotation(annot: AnnotationInfo) = annot matches TypeConstraintClass } + trait VariantTypeMap extends TypeMap { + private[this] var _variance = 1 + + override def variance = _variance + def variance_=(x: Int) = _variance = x + + override protected def noChangeToSymbols(origSyms: List[Symbol]) = { + origSyms forall { sym => + val v = variance + if (sym.isAliasType) variance = 0 + val result = this(sym.info) + variance = v + result eq sym.info + } + } + + override protected 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 type */ + override def mapOver(tp: Type): Type = tp match { + case MethodType(params, result) => + variance = -variance + val params1 = mapOver(params) + variance = -variance + val result1 = this(result) + if ((params1 eq params) && (result1 eq result)) tp + 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 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 TypeRef(pre, sym, args) => + val pre1 = this(pre) + val args1 = + if (args.isEmpty) + args + else if (variance == 0) // fast & safe path: don't need to look at typeparams + args mapConserve this + else { + val tparams = sym.typeParams + if (tparams.isEmpty) args + else mapOverArgs(args, tparams) + } + if ((pre1 eq pre) && (args1 eq args)) tp + else copyTypeRef(tp, pre1, coevolveSym(pre, pre1, sym), args1) + case _ => + super.mapOver(tp) + } + } + /** A prototype for mapping a function over all possible types */ - abstract class TypeMap extends Function1[Type, Type] { + abstract class TypeMap extends (Type => Type) { 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. + /** Mix in VariantTypeMap if you want variances to be significant. */ - var variance = 0 + def variance = 0 // #3731: return sym1 for which holds: pre bound sym.name to sym and // pre1 now binds sym.name to sym1, conceptually exactly the same @@ -3354,17 +3538,7 @@ A type's typeSymbol should never be inspected directly. 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 if (variance == 0) // fast & safe path: don't need to look at typeparams - args mapConserve this - else { - val tparams = sym.typeParams - if (tparams.isEmpty) args - else mapOverArgs(args, tparams) - } + val args1 = args mapConserve this if ((pre1 eq pre) && (args1 eq args)) tp else copyTypeRef(tp, pre1, coevolveSym(pre, pre1, sym), args1) case ThisType(_) => tp @@ -3376,16 +3550,12 @@ A type's typeSymbol should never be inspected directly. 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 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)) @@ -3400,9 +3570,7 @@ A type's typeSymbol should never be inspected directly. 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) @@ -3420,7 +3588,7 @@ A type's typeSymbol should never be inspected directly. val tparams1 = mapOver(tparams) var result1 = this(result) if ((tparams1 eq tparams) && (result1 eq result)) tp - else ExistentialType(tparams1, result1.substSym(tparams, tparams1)) + else newExistentialType(tparams1, result1.substSym(tparams, tparams1)) case OverloadedType(pre, alts) => val pre1 = if (pre.isInstanceOf[ClassInfoType]) pre else this(pre) if (pre1 eq pre) tp @@ -3458,15 +3626,14 @@ A type's typeSymbol should never be inspected directly. // throw new Error("mapOver inapplicable for " + tp); } - protected final 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 - } + protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] = + args mapConserve this + + /** Called by mapOver to determine whether the original symbols can + * be returned, or whether they must be cloned. Overridden in VariantTypeMap. + */ + protected def noChangeToSymbols(origSyms: List[Symbol]) = + origSyms forall (sym => sym.info eq this(sym.info)) /** Map this function over given scope */ def mapOver(scope: Scope): Scope = { @@ -3475,20 +3642,13 @@ A type's typeSymbol should never be inspected directly. 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 - } - // map is not the identity --> do cloning properly - if (change) cloneSymbolsAndModify(origSyms, TypeMap.this) // fast path in case nothing changes due to map - else origSyms + if (noChangeToSymbols(origSyms)) origSyms + // map is not the identity --> do cloning properly + else cloneSymbolsAndModify(origSyms, TypeMap.this) } def mapOver(annot: AnnotationInfo): AnnotationInfo = { @@ -3555,13 +3715,25 @@ A type's typeSymbol should never be inspected directly. } } - private val emptySymMap = immutable.Map[Symbol, Symbol]() - private val emptySymCount = immutable.Map[Symbol, Int]() + /** A collector that tests for existential types appearing at given variance in a type + * @PP: Commenting out due to not being used anywhere. + */ + // class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) with VariantTypeMap { + // variance = v + // + // def traverse(tp: Type) = tp match { + // case ExistentialType(_, _) if (variance == v) => result = true + // case _ => mapOver(tp) + // } + // } + // + // val containsCovariantExistentialCollector = new ContainsVariantExistentialCollector(1) + // val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1) 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) - } + val eparams = mapWithIndex(tparams)((tparam, i) => + clazz.newExistential(clazz.pos, newTypeName("?"+i)) setInfo tparam.info.bounds) + eparams map (_ substInfo (tparams, eparams)) } @@ -3608,6 +3780,62 @@ A type's typeSymbol should never be inspected directly. mapOver(tp) } } + + /** Used by existentialAbstraction. + */ + class ExistentialExtrapolation(tparams: List[Symbol]) extends VariantTypeMap { + private val occurCount = mutable.HashMap[Symbol, Int]() + private def countOccs(tp: Type) = { + tp foreach { + case TypeRef(_, sym, _) => + if (tparams contains sym) + occurCount(sym) += 1 + case _ => () + } + } + def extrapolate(tpe: Type): Type = { + tparams foreach (t => occurCount(t) = 0) + countOccs(tpe) + for (tparam <- tparams) + countOccs(tparam.info) + + apply(tpe) + } + + def apply(tp: Type): Type = { + val tp1 = mapOver(tp) + if (variance == 0) tp1 + else tp1 match { + case TypeRef(pre, sym, args) if tparams contains 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.isBottomClass && 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) + } + + // 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. + override def mapOver(tree: Tree) = tree match { + case Ident(_) if tree.tpe.isStable => tree + case _ => super.mapOver(tree) + } + } def singletonBounds(hi: Type) = TypeBounds.upper(intersectionType(List(hi, SingletonClass.tpe))) @@ -3615,6 +3843,7 @@ A type's typeSymbol should never be inspected directly. class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap with KeepOnlyTypeConstraints { var capturedSkolems: List[Symbol] = List() var capturedParams: List[Symbol] = List() + var capturedPre = emptySymMap override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { object annotationArgRewriter extends TypeMapTransformer { @@ -3645,8 +3874,6 @@ A type's typeSymbol should never be inspected directly. annotationArgRewriter.transform(tree) } - var capturedPre = emptySymMap - def stabilize(pre: Type, clazz: Symbol): Type = capturedPre.getOrElse(clazz, { val qvar = clazz freshExistential ".type" setInfo singletonBounds(pre) @@ -3789,7 +4016,7 @@ A type's typeSymbol should never be inspected directly. case PolyType(bs, restp) => createFromClonedSymbols(bs, restp)((ps1, tp1) => PolyType(ps1, renameBoundSyms(tp1))) case ExistentialType(bs, restp) => - createFromClonedSymbols(bs, restp)(ExistentialType(_, _)) + createFromClonedSymbols(bs, restp)(newExistentialType) case _ => tp } @@ -4041,7 +4268,7 @@ A type's typeSymbol should never be inspected directly. case WildcardType => TypeVar(tp, new TypeConstraint) case BoundedWildcardType(bounds) => - TypeVar(tp, new TypeConstraint(List(bounds.lo), List(bounds.hi))) + TypeVar(tp, new TypeConstraint(bounds)) case _ => mapOver(tp) } @@ -4094,9 +4321,13 @@ A type's typeSymbol should never be inspected directly. } /** A map to implement the `filter` method. */ - class FilterTypeCollector(p: Type => Boolean) extends TypeCollector(new ListBuffer[Type]) { + class FilterTypeCollector(p: Type => Boolean) extends TypeCollector[List[Type]](Nil) { + def withFilter(q: Type => Boolean) = new FilterTypeCollector(tp => p(tp) && q(tp)) + + override def collect(tp: Type) = super.collect(tp).reverse + def traverse(tp: Type) { - if (p(tp)) result += tp + if (p(tp)) result ::= tp mapOver(tp) } } @@ -4180,10 +4411,14 @@ A type's typeSymbol should never be inspected directly. definitions.RootPackage } else if (sym.isModuleClass) { val sourceModule1 = adaptToNewRun(pre, sym.sourceModule) - val result = sourceModule1.moduleClass - val msg = "sym = %s, sourceModule = %s, sourceModule.moduleClass = %s => sourceModule1 = %s, sourceModule1.moduleClass = %s" - assert(result != NoSymbol, msg.format(sym, sym.sourceModule, sym.sourceModule.moduleClass, sourceModule1, sourceModule1.moduleClass)) - result + var result = sourceModule1.moduleClass + if (result == NoSymbol) result = sourceModule1.initialize.moduleClass + if (result != NoSymbol) result + else { + val msg = "Cannot adapt module class; sym = %s, sourceModule = %s, sourceModule.moduleClass = %s => sourceModule1 = %s, sourceModule1.moduleClass = %s" + debuglog(msg.format(sym, sym.sourceModule, sym.sourceModule.moduleClass, sourceModule1, sourceModule1.moduleClass)) + sym + } } else if ((pre eq NoPrefix) || (pre eq NoType) || sym.isPackageClass) { sym } else { @@ -4333,8 +4568,7 @@ A type's typeSymbol should never be inspected directly. case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => assert(sym1 == sym2) pre1 =:= pre2 && - ((args1, args2, sym1.typeParams).zipped forall { - (arg1, arg2, tparam) => + forall3(args1, args2, sym1.typeParams) { (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]) @@ -4344,7 +4578,7 @@ A type's typeSymbol should never be inspected directly. // 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) => @@ -4867,19 +5101,11 @@ A type's typeSymbol should never be inspected directly. // --> 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) + corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg) def differentOrNone(tp1: Type, tp2: Type) = if (tp1 eq tp2) NoType else tp1 @@ -5251,7 +5477,6 @@ A type's typeSymbol should never be inspected directly. 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) { @@ -5260,15 +5485,17 @@ A type's typeSymbol should never be inspected directly. 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))) { + foreach3(tvars, tparams, variances)((tvar2, tparam2, variance2) => { + val ok = (tparam2 != tparam) && ( + (bound contains tparam2) + || up && (tparam2.info.bounds.lo =:= tparam.tpe) + || !up && (tparam2.info.bounds.hi =:= tparam.tpe) + ) + if (ok) { if (tvar2.constr.inst eq null) cyclic = true solveOne(tvar2, tparam2, variance2) } - } + }) if (!cyclic) { if (up) { if (bound.typeSymbol != AnyClass) @@ -5307,9 +5534,7 @@ A type's typeSymbol should never be inspected directly. } // println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info))) - for ((tvar, (tparam, variance)) <- config) - solveOne(tvar, tparam, variance) - + foreach3(tvars, tparams, variances)(solveOne) tvars forall (tvar => tvar.constr.isWithinBounds(tvar.constr.inst)) } @@ -5357,6 +5582,23 @@ A type's typeSymbol should never be inspected directly. val formatted = tableDef.table(transposed) println("** Depth is " + depth + "\n" + formatted) } + + /** From a list of types, find any which take type parameters + * where the type parameter bounds contain references to other + * any types in the list (including itself.) + * + * @return List of symbol pairs holding the recursive type + * parameter and the parameter which references it. + */ + def findRecursiveBounds(ts: List[Type]): List[(Symbol, Symbol)] = { + if (ts.isEmpty) Nil + else { + val sym = ts.head.typeSymbol + require(ts.tail forall (_.typeSymbol == sym), ts) + for (p <- sym.typeParams ; in <- sym.typeParams ; if in.info.bounds contains p) yield + p -> in + } + } /** Given a matrix `tsBts` whose columns are basetype sequences (and the symbols `tsParams` that should be interpreted as type parameters in this matrix), * compute its least sorted upwards closed upper bound relative to the following ordering <= between lists of types: @@ -5403,6 +5645,19 @@ A type's typeSymbol should never be inspected directly. // merging, strip targs that refer to bound tparams (when we're computing the lub of type // constructors.) Also filter out all types that are a subtype of some other type. if (isUniformFrontier) { + if (settings.debug.value || printLubs) { + val fbounds = findRecursiveBounds(ts0) + if (fbounds.nonEmpty) { + println("Encountered " + fbounds.size + " recursive bounds while lubbing " + ts0.size + " types.") + for ((p0, p1) <- fbounds) { + val desc = if (p0 == p1) "its own bounds" else "the bounds of " + p1 + + println(" " + p0.fullLocationString + " appears in " + desc) + println(" " + p1 + " " + p1.info.bounds) + } + println("") + } + } val tails = tsBts map (_.tail) mergePrefixAndArgs(elimSub(ts0 map elimHigherOrderTypeParam, depth), 1, depth) match { case Some(tp) => tp :: loop(tails) @@ -5428,7 +5683,7 @@ A type's typeSymbol should never be inspected directly. } } - val initialBTSes = ts map (_.baseTypeSeq.toList) + val initialBTSes = ts map (_.baseTypeSeq.toList filter (_.typeSymbol.isPublic)) if (printLubs) printLubMatrix(ts zip initialBTSes toMap, depth) @@ -5471,22 +5726,11 @@ A type's typeSymbol should never be inspected directly. case _ => t } - - /** 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 - } + def elimRefinement(t: Type) = t match { + case RefinedType(parents, decls) if !decls.isEmpty => intersectionType(parents) + case _ => t } - 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] = { @@ -5603,8 +5847,8 @@ A type's typeSymbol should never be inspected directly. 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))) + val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((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)))) @@ -5632,9 +5876,16 @@ A type's typeSymbol should never be inspected directly. val lubType = if (phase.erasedTypes || depth == 0) lubBase else { - val lubRefined = refinedType(lubParents, lubOwner) + val lubRefined = refinedType(lubParents, lubOwner) val lubThisType = lubRefined.typeSymbol.thisType - val narrowts = ts map (_.narrow) + val narrowts = ts map (_.narrow) + def excludeFromLub(sym: Symbol) = ( + sym.isClass + || sym.isConstructor + || !sym.isPublic + || isGetClass(sym) + || narrowts.exists(t => !refines(t, sym)) + ) def lubsym(proto: Symbol): Symbol = { val prototp = lubThisType.memberInfo(proto) val syms = narrowts map (t => @@ -5643,7 +5894,7 @@ A type's typeSymbol should never be inspected directly. if (syms contains NoSymbol) NoSymbol else { val symtypes = - (narrowts, syms).zipped map ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)) + map2(narrowts, syms)((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 =:=)) @@ -5663,16 +5914,15 @@ A type's typeSymbol should never be inspected directly. // 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 && !isGetClass(sym) && (narrowts forall (t => refines(t, sym)))) - try { - val lsym = lubsym(sym) - if (lsym != NoSymbol) addMember(lubThisType, lubRefined, lubsym(sym)) - } catch { - case ex: NoCommonType => - } + // add a refinement symbol for all non-class members of lubBase + // which are refined by every type in ts. + for (sym <- lubBase.nonPrivateMembers ; if !excludeFromLub(sym)) { + try { + val lsym = lubsym(sym) + if (lsym != NoSymbol) addMember(lubThisType, lubRefined, lsym) + } catch { + case ex: NoCommonType => + } } if (lubRefined.decls.isEmpty) lubBase else if (!verifyLubs) lubRefined @@ -5705,7 +5955,7 @@ A type's typeSymbol should never be inspected directly. } val res = lub0(ts) if (printLubs) { - indent = indent dropRight 2 + indent = indent stripSuffix " " println(indent + "lub of " + ts + " is " + res)//debug } if (ts forall (_.isNotNull)) res.notNull else res @@ -5748,8 +5998,8 @@ A type's typeSymbol should never be inspected directly. 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))) + val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) => + tparam.cloneSymbol.setInfo(lub(bounds, depth))) PolyType(tparams1, glbNorm(matchingInstTypes(ts, tparams1), depth)) case ts @ MethodType(params, _) :: rest => MethodType(params, glbNorm(matchingRestypes(ts, params map (_.tpe)), depth)) @@ -5880,38 +6130,39 @@ A type's typeSymbol should never be inspected directly. 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) { - // Take the intersection of the upper bounds of the type parameters - // rather than falling all the way back to "Any", otherwise we end up not - // conforming to bounds. - val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass) - if (bounds0.isEmpty) AnyClass.tpe - else intersectionType(bounds0) - } - else if (tparam.variance == -variance) NothingClass.tpe - else NoType + } + else { + val args = map2(sym.typeParams, argss.transpose) { (tparam, as) => + if (depth == 0) { + if (tparam.variance == variance) { + // Take the intersection of the upper bounds of the type parameters + // rather than falling all the way back to "Any", otherwise we end up not + // conforming to bounds. + val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass) + if (bounds0.isEmpty) AnyClass.tpe + else intersectionType(bounds0 map (b => b.asSeenFrom(tps.head, sym))) } + 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 { - 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 - } + 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))) } @@ -5996,148 +6247,6 @@ A type's typeSymbol should never be inspected directly. 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 `sym1`'s variance conforms to `sym2`'s variance. - * - * If `sym2` is invariant, `sym1`'s variance is irrelevant. Otherwise they must be equal. - */ - def variancesMatch(sym1: Symbol, sym2: Symbol): Boolean = (sym2.variance==0 || sym1.variance==sym2.variance) - - // check that the type parameters <arg>hkargs</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) - val declaredBounds = transformedBounds(hkparam, paramowner) - val declaredBoundsInst = bindHKParams(declaredBounds) - val argumentBounds = transform(hkarg.info.bounds, owner) - if (!(declaredBoundsInst <:< argumentBounds)) - stricterBound(hkarg, hkparam) - - debuglog( - "checkKindBoundsHK base case: " + hkparam + - " declared bounds: " + declaredBounds + - " after instantiating earlier hkparams: " + declaredBoundsInst + "\n" + - "checkKindBoundsHK base case: "+ hkarg + - " has bounds: " + argumentBounds - ) - } - else { - debuglog("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg) - val (am, vm, sb) = checkKindBoundsHK( - hkarg.typeParams, - hkarg, - hkparam, - paramowner, - underHKParams ++ hkparam.typeParams, - withHKArgs ++ hkarg.typeParams - ) - arityMismatches(am) - varianceMismatches(vm) - stricterBounds(sb) - } - if (!explainErrors && error) return (Nil, Nil, Nil) // stop as soon as we encountered an error - } - if (!explainErrors) (Nil, Nil, Nil) - else (_arityMismatches.toList, _varianceMismatches.toList, _stricterBounds.toList) - } - } - - val errors = new ListBuffer[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] - if (settings.debug.value &&(tparams.nonEmpty || targs.nonEmpty)) - log("checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", " + owner + ", " + explainErrors + ")") - - for { - (tparam, targ) <- tparams zip targs - // Prevent WildcardType from causing kind errors, as typevars may be higher-order - if (targ != WildcardType) && (targ.isHigherKinded || tparam.typeParams.nonEmpty) - } { - // @M must use the typeParams of the *type* targ, not of the *symbol* of targ!! - targ.typeSymbolDirect.info // force symbol load for #4205 - val tparamsHO = targ.typeParams - - val (arityMismatches, varianceMismatches, stricterBounds) = ( - // NOTE: *not* targ.typeSymbol, which normalizes - checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) - ) - if (explainErrors) { - if (arityMismatches.nonEmpty || varianceMismatches.nonEmpty || stricterBounds.nonEmpty) { - errors += ((targ, tparam, arityMismatches, varianceMismatches, stricterBounds)) - } - } - else if (error) - return List((NoType, NoSymbol, Nil, Nil, Nil)) - } - - errors.toList - } - // Errors and Diagnostics ----------------------------------------------------- /** A throwable signalling a type error */ @@ -6164,7 +6273,7 @@ A type's typeSymbol should never be inspected directly. Console.println(indent + tp1 + " " + op + " " + arg2 + "?" /* + "("+tp1.getClass+","+arg2.getClass+")"*/) indent = indent + " " val result = p(tp1, arg2) - indent = indent dropRight 2 + indent = indent stripSuffix " " Console.println(indent + result) result } diff --git a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala index 9aa3d8a2c3..0789f9c774 100644 --- a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala @@ -46,7 +46,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { } } - class Scan(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) extends PickleBuffer(bytes, offset, -1) { + 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 @@ -184,6 +184,8 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { case _ => errorBadSignature("bad name tag: " + tag) } } + protected def readTermName(): TermName = readName().toTermName + protected def readTypeName(): TypeName = readName().toTypeName /** Read a symbol */ protected def readSymbol(): Symbol = { @@ -211,7 +213,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { return NoSymbol if (tag == EXTMODCLASSref) { - val moduleVar = owner.info.decl(nme.moduleVarName(name)) + val moduleVar = owner.info.decl(nme.moduleVarName(name.toTermName)) if (moduleVar.isLazyAccessor) return moduleVar.lazyAccessor.lazyAccessor } @@ -223,7 +225,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { // (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 { + fromName(nme.expandedName(name.toTermName, owner)) orElse { // (3) Try as a nested object symbol. nestedObjectSymbol orElse { // (4) Otherwise, fail. @@ -296,14 +298,14 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { 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) + val m = owner.newModule(name.toTermName, clazz) clazz.sourceModule = m m } case VALsym => if (isModuleRoot) { assert(false); NoSymbol } - else if (isMethodFlag) owner.newMethod(name) - else owner.newValue(name) + else if (isMethodFlag) owner.newMethod(name.toTermName) + else owner.newValue(name.toTermName) case _ => errorBadSignature("bad symbol tag: " + tag) @@ -378,7 +380,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { // that it isn't right here. See #4757 for the immediate // motivation to fix it. val tparams = until(end, readSymbolRef) map (_ setFlag EXISTENTIAL) - ExistentialType(tparams, restpe) + newExistentialType(tparams, restpe) case ANNOTATEDtpe => var typeRef = readNat() @@ -549,13 +551,13 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { case MODULEtree => setSymModsName() - ModuleDef(mods, name, readTemplateRef()) + ModuleDef(mods, name.toTermName, readTemplateRef()) case VALDEFtree => setSymModsName() val tpt = readTreeRef() val rhs = readTreeRef() - ValDef(mods, name, tpt, rhs) + ValDef(mods, name.toTermName, tpt, rhs) case DEFDEFtree => setSymModsName() @@ -563,7 +565,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { val vparamss = times(readNat(), () => times(readNat(), readValDefRef)) val tpt = readTreeRef() val rhs = readTreeRef() - DefDef(mods, name, tparams, vparamss, tpt, rhs) + DefDef(mods, name.toTermName, tparams, vparamss, tpt, rhs) case TYPEDEFtree => setSymModsName() @@ -575,7 +577,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { setSymName() val rhs = readTreeRef() val params = until(end, readIdentRef) - LabelDef(name, params, rhs) + LabelDef(name.toTermName, params, rhs) case IMPORTtree => setSym() diff --git a/src/compiler/scala/reflect/internal/util/Collections.scala b/src/compiler/scala/reflect/internal/util/Collections.scala new file mode 100644 index 0000000000..94672097c4 --- /dev/null +++ b/src/compiler/scala/reflect/internal/util/Collections.scala @@ -0,0 +1,158 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.reflect.internal.util + +import scala.collection.{ mutable, immutable } +import scala.annotation.tailrec +import mutable.ListBuffer + +/** Profiler driven changes. + */ +trait Collections { + /** 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) + ) + + /** All these mm methods are "deep map" style methods for + * mapping etc. on a list of lists. + */ + final def mexists[A](xss: List[List[A]])(p: A => Boolean) = + xss exists (_ exists p) + final def mmap[A, B](xss: List[List[A]])(f: A => B) = + xss map (_ map f) + final def mforeach[A](xss: List[List[A]])(f: A => Unit) = + xss foreach (_ foreach f) + final def mfind[A](xss: List[List[A]])(p: A => Boolean): Option[A] = { + for (xs <- xss; x <- xs) + if (p(x)) return Some(x) + None + } + final def mfilter[A](xss: List[List[A]])(p: A => Boolean) = + for (xs <- xss; x <- xs; if p(x)) yield x + + final def map2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => C): List[C] = { + val lb = new ListBuffer[C] + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + lb += f(ys1.head, ys2.head) + ys1 = ys1.tail + ys2 = ys2.tail + } + lb.toList + } + final def map3[A, B, C, D](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => D): List[D] = { + if (xs1.isEmpty || xs2.isEmpty || xs3.isEmpty) Nil + else f(xs1.head, xs2.head, xs3.head) :: map3(xs1.tail, xs2.tail, xs3.tail)(f) + } + final def flatMap2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => List[C]): List[C] = { + val lb = new ListBuffer[C] + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + lb ++= f(ys1.head, ys2.head) + ys1 = ys1.tail + ys2 = ys2.tail + } + lb.toList + } + + final def mapWithIndex[A, B](xs: List[A])(f: (A, Int) => B): List[B] = { + val lb = new ListBuffer[B] + var index = 0 + var ys = xs + while (!ys.isEmpty) { + lb += f(ys.head, index) + ys = ys.tail + index += 1 + } + lb.toList + } + final def collectMap2[A, B, C](xs1: List[A], xs2: List[B])(p: (A, B) => Boolean): Map[A, B] = { + if (xs1.isEmpty || xs2.isEmpty) + return Map() + + val buf = immutable.Map.newBuilder[A, B] + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + val x1 = ys1.head + val x2 = ys2.head + if (p(x1, x2)) + buf += ((x1, x2)) + + ys1 = ys1.tail + ys2 = ys2.tail + } + buf.result + } + final def foreach2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Unit): Unit = { + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + f(ys1.head, ys2.head) + ys1 = ys1.tail + ys2 = ys2.tail + } + } + final def foreach3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Unit): Unit = { + var ys1 = xs1 + var ys2 = xs2 + var ys3 = xs3 + while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) { + f(ys1.head, ys2.head, ys3.head) + ys1 = ys1.tail + ys2 = ys2.tail + ys3 = ys3.tail + } + } + final def exists2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + if (f(ys1.head, ys2.head)) + return true + + ys1 = ys1.tail + ys2 = ys2.tail + } + false + } + final def forall2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + if (!f(ys1.head, ys2.head)) + return false + + ys1 = ys1.tail + ys2 = ys2.tail + } + true + } + final def forall3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + var ys3 = xs3 + while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) { + if (!f(ys1.head, ys2.head, ys3.head)) + return false + + ys1 = ys1.tail + ys2 = ys2.tail + ys3 = ys3.tail + } + true + } +} + +object Collections extends Collections { } + diff --git a/src/compiler/scala/reflect/internal/util/Origins.scala b/src/compiler/scala/reflect/internal/util/Origins.scala new file mode 100644 index 0000000000..b9985c8f50 --- /dev/null +++ b/src/compiler/scala/reflect/internal/util/Origins.scala @@ -0,0 +1,107 @@ +/* NSC -- new scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.reflect +package internal.util + +import NameTransformer._ +import scala.collection.{ mutable, immutable } +import Origins._ + +/** A debugging class for logging from whence a method is being called. + * Say you wanted to discover who was calling phase_= in SymbolTable. + * You could do this: + * + * {{{ + * private lazy val origins = Origins[SymbolTable]("phase_=") + * // Commented out original enclosed for contrast + * // final def phase_=(p: Phase): Unit = { + * final def phase_=(p: Phase): Unit = origins { + * }}} + * + * And that's it. When the JVM exits it would issue a report something like this: + {{{ + >> Origins scala.tools.nsc.symtab.SymbolTable.phase_= logged 145585 calls from 51 distinguished sources. + + 71114 scala.tools.nsc.symtab.Symbols$Symbol.unsafeTypeParams(Symbols.scala:862) + 16584 scala.tools.nsc.symtab.Symbols$Symbol.rawInfo(Symbols.scala:757) + 15411 scala.tools.nsc.symtab.Symbols$Symbol.unsafeTypeParams(Symbols.scala:869) + 11507 scala.tools.nsc.symtab.Symbols$Symbol.rawInfo(Symbols.scala:770) + 10285 scala.tools.nsc.symtab.Symbols$Symbol.unsafeTypeParams(Symbols.scala:864) + 6860 scala.tools.nsc.transform.SpecializeTypes.specializedTypeVars(SpecializeTypes.scala:304) + ... + }}} + * + */ +abstract class Origins { + type Rep + def newRep(xs: StackSlice): Rep + def repString(rep: Rep): String + def originClass: String + + private var _tag: String = null + def tag: String = _tag + def setTag(tag: String): this.type = { + _tag = tag + this + } + + private val origins = new mutable.HashMap[Rep, Int] withDefaultValue 0 + private def add(xs: Rep) = origins(xs) += 1 + private def total = origins.values.foldLeft(0L)(_ + _) + + // We find the right line by dropping any from around here and any + // from the method's origin class. + private def dropStackElement(cn: String) = + (cn startsWith OriginsName) || (cn startsWith originClass) + + // Create a stack and whittle it down to the interesting part. + private def readStack(): Array[StackTraceElement] = + (new Throwable).getStackTrace dropWhile (el => dropStackElement(el.getClassName)) + + def apply[T](body: => T): T = { + add(newRep(readStack())) + body + } + def clear() = origins.clear() + def show() = { + println("\n>> Origins %s.%s logged %s calls from %s distinguished sources.\n".format(originClass, tag, total, origins.keys.size)) + origins.toList sortBy (-_._2) foreach { + case (k, v) => println("%7s %s".format(v, repString(k))) + } + } + def purge() = { + show() + clear() + } +} + +object Origins { + private type StackSlice = Array[StackTraceElement] + private val OriginsName = classOf[Origins].getName + private val counters = new mutable.HashSet[Origins] + + { + // Console.println("\nOrigins loaded: registering shutdown hook to display results.") + sys.addShutdownHook(counters foreach (_.purge())) + } + + def apply[T: Manifest](tag: String): Origins = apply(tag, manifest[T].erasure) + def apply(tag: String, clazz: Class[_]): Origins = apply(tag, new OneLine(clazz)) + def apply(tag: String, orElse: => Origins): Origins = { + counters find (_.tag == tag) getOrElse { + val res = orElse setTag tag + counters += res + res + } + } + + class OneLine(clazz: Class[_]) extends Origins { + type Rep = StackTraceElement + val originClass = clazz.getName stripSuffix MODULE_SUFFIX_STRING + def newRep(xs: StackSlice): Rep = xs(0) + def repString(rep: Rep) = " " + rep + } +} |