diff options
Diffstat (limited to 'src')
145 files changed, 3127 insertions, 2662 deletions
diff --git a/src/compiler/scala/reflect/internal/AnnotationInfos.scala b/src/compiler/scala/reflect/internal/AnnotationInfos.scala index 665e33e783..255e69c3c6 100644 --- a/src/compiler/scala/reflect/internal/AnnotationInfos.scala +++ b/src/compiler/scala/reflect/internal/AnnotationInfos.scala @@ -230,10 +230,8 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable => def refsSymbol(sym: Symbol) = hasArgWhich(_.symbol == sym) /** Change all ident's with Symbol "from" to instead use symbol "to" */ - def substIdentSyms(from: Symbol, to: Symbol) = { - val subs = new TreeSymSubstituter(List(from), List(to)) - AnnotationInfo(atp, args.map(subs(_)), assocs).setPos(pos) - } + def substIdentSyms(from: Symbol, to: Symbol) = + AnnotationInfo(atp, args map (_ substTreeSyms (from -> to)), assocs) setPos pos def stringArg(index: Int) = constantAtIndex(index) map (_.stringValue) def intArg(index: Int) = constantAtIndex(index) map (_.intValue) diff --git a/src/compiler/scala/reflect/internal/ClassfileConstants.scala b/src/compiler/scala/reflect/internal/ClassfileConstants.scala index 136350ebbb..f1bf41ede9 100644 --- a/src/compiler/scala/reflect/internal/ClassfileConstants.scala +++ b/src/compiler/scala/reflect/internal/ClassfileConstants.scala @@ -6,6 +6,8 @@ package scala.reflect package internal +import annotation.switch + object ClassfileConstants { final val JAVA_MAGIC = 0xCAFEBABE @@ -326,28 +328,62 @@ object ClassfileConstants { final val impdep1 = 0xfe final val impdep2 = 0xff - def toScalaFlags(flags: Int, isClass: Boolean = false, isField: Boolean = false): Long = { + abstract class FlagTranslation { import Flags._ - var res = 0l - if ((flags & JAVA_ACC_PRIVATE) != 0) - res = res | PRIVATE - else if ((flags & JAVA_ACC_PROTECTED) != 0) - res = res | PROTECTED - if ((flags & JAVA_ACC_ABSTRACT) != 0 && (flags & JAVA_ACC_ANNOTATION) == 0) - res = res | DEFERRED - if ((flags & JAVA_ACC_FINAL) != 0) - res = res | FINAL - if (((flags & JAVA_ACC_INTERFACE) != 0) && - ((flags & JAVA_ACC_ANNOTATION) == 0)) - res = res | TRAIT | INTERFACE | ABSTRACT - if ((flags & JAVA_ACC_SYNTHETIC) != 0) - res = res | SYNTHETIC - if ((flags & JAVA_ACC_STATIC) != 0) - res = res | STATIC - if (isClass && ((res & DEFERRED) != 0L)) - res = res & ~DEFERRED | ABSTRACT - if (isField && (res & FINAL) == 0L) - res = res | MUTABLE - res | JAVA + + private var isAnnotation = false + private var isClass = false + private def initFields(flags: Int) = { + isAnnotation = (flags & JAVA_ACC_ANNOTATION) != 0 + isClass = false + } + private def translateFlag(jflag: Int): Long = (jflag: @switch) match { + case JAVA_ACC_PRIVATE => PRIVATE + case JAVA_ACC_PROTECTED => PROTECTED + case JAVA_ACC_FINAL => FINAL + case JAVA_ACC_SYNTHETIC => SYNTHETIC + case JAVA_ACC_STATIC => STATIC + case JAVA_ACC_ABSTRACT => if (isAnnotation) 0L else if (isClass) ABSTRACT else DEFERRED + case JAVA_ACC_INTERFACE => if (isAnnotation) 0L else TRAIT | INTERFACE | ABSTRACT + case _ => 0L + } + private def translateFlags(jflags: Int, baseFlags: Long): Long = { + var res: Long = JAVA | baseFlags + /** fast, elegant, maintainable, pick any two... */ + res |= translateFlag(jflags & JAVA_ACC_PRIVATE) + res |= translateFlag(jflags & JAVA_ACC_PROTECTED) + res |= translateFlag(jflags & JAVA_ACC_FINAL) + res |= translateFlag(jflags & JAVA_ACC_SYNTHETIC) + res |= translateFlag(jflags & JAVA_ACC_STATIC) + res |= translateFlag(jflags & JAVA_ACC_ABSTRACT) + res |= translateFlag(jflags & JAVA_ACC_INTERFACE) + res + } + + def classFlags(jflags: Int): Long = { + initFields(jflags) + isClass = true + translateFlags(jflags, 0) + } + def fieldFlags(jflags: Int): Long = { + initFields(jflags) + translateFlags(jflags, if ((jflags & JAVA_ACC_FINAL) == 0) MUTABLE else 0) + } + def methodFlags(jflags: Int): Long = { + initFields(jflags) + translateFlags(jflags, 0) + } } + object FlagTranslation extends FlagTranslation { } + + def toScalaMethodFlags(flags: Int): Long = FlagTranslation methodFlags flags + def toScalaClassFlags(flags: Int): Long = FlagTranslation classFlags flags + def toScalaFieldFlags(flags: Int): Long = FlagTranslation fieldFlags flags + + @deprecated("Use another method in this object", "2.10.0") + def toScalaFlags(flags: Int, isClass: Boolean = false, isField: Boolean = false): Long = ( + if (isClass) toScalaClassFlags(flags) + else if (isField) toScalaFieldFlags(flags) + else toScalaMethodFlags(flags) + ) } diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index d3af8e2623..02d6737bdb 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -14,13 +14,28 @@ import PartialFunction._ trait Definitions extends reflect.api.StandardDefinitions { self: SymbolTable => + private def newClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): Symbol = { + val clazz = owner.newClassSymbol(name, NoPosition, flags) + clazz setInfoAndEnter ClassInfoType(parents, new Scope, clazz) + } + private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): Symbol = { + val msym = owner.newMethod(name.encode, NoPosition, flags) + val params = msym.newSyntheticValueParams(formals) + msym setInfoAndEnter MethodType(params, restpe) + } + // the scala value classes trait ValueClassDefinitions { self: definitions.type => private[Definitions] def valueCache(name: Name) = { - if (name.isTypeName) ScalaPackageClass.info member name - else ScalaPackageClass.info member name suchThat (_ hasFlag MODULE) + val res = ( + if (name.isTypeName) ScalaPackageClass.info member name + else ScalaPackageClass.info member name suchThat (_ hasFlag MODULE) + ) + if (res eq NoSymbol) + abort("Could not find value classes! This is a catastrophic failure. scala " + scala.util.Properties.versionString) + else res } private[Definitions] def valueModuleMethod(className: Name, methodName: Name): Symbol = { valueCache(className.toTermName).moduleClass.tpe member methodName @@ -66,13 +81,6 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val boxMethod = classesMap(x => valueModuleMethod(x, nme.box)) lazy val unboxMethod = classesMap(x => valueModuleMethod(x, nme.unbox)) - private def newClass(owner: Symbol, name: TypeName, parents: List[Type]): Symbol = { - val clazz = owner.newClass(NoPosition, name) - clazz.setInfo(ClassInfoType(parents, new Scope, clazz)) - owner.info.decls.enter(clazz) - clazz - } - def isNumericSubClass(sub: Symbol, sup: Symbol) = ( (numericWeight contains sub) && (numericWeight contains sup) @@ -124,21 +132,21 @@ trait Definitions extends reflect.api.StandardDefinitions { // This is the package _root_. The actual root cannot be referenced at // the source level, but _root_ is essentially a function () => <root>. lazy val RootPackage: Symbol = { - val rp = NoSymbol.newValue(NoPosition, nme.ROOTPKG) - .setFlag(FINAL | MODULE | PACKAGE | JAVA) - .setInfo(NullaryMethodType(RootClass.tpe)) + val rp = ( + NoSymbol.newValue(nme.ROOTPKG, NoPosition, FINAL | MODULE | PACKAGE | JAVA) + setInfo NullaryMethodType(RootClass.tpe) + ) RootClass.sourceModule = rp rp } // This is the actual root of everything, including the package _root_. lazy val RootClass: ModuleClassSymbol = ( - NoSymbol.newModuleClass(NoPosition, tpnme.ROOT) - setFlag (FINAL | MODULE | PACKAGE | JAVA) + NoSymbol.newModuleClassSymbol(tpnme.ROOT, NoPosition, FINAL | MODULE | PACKAGE | JAVA) setInfo rootLoader ) // The empty package, which holds all top level types without given packages. - lazy val EmptyPackage = RootClass.newPackage(NoPosition, nme.EMPTY_PACKAGE_NAME).setFlag(FINAL) + lazy val EmptyPackage = RootClass.newPackage(nme.EMPTY_PACKAGE_NAME, NoPosition, FINAL) lazy val EmptyPackageClass = EmptyPackage.moduleClass lazy val JavaLangPackage = getModule(sn.JavaLang) @@ -190,11 +198,11 @@ trait Definitions extends reflect.api.StandardDefinitions { } // top types - lazy val AnyClass = newClass(ScalaPackageClass, tpnme.Any, Nil) setFlag (ABSTRACT) + lazy val AnyClass = newClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.typeConstructor) lazy val ObjectClass = getClass(sn.Object) - lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") setFlag (SEALED | ABSTRACT | TRAIT) - lazy val AnyValCompanionClass = getRequiredClass("scala.AnyValCompanion") setFlag (SEALED | ABSTRACT | TRAIT) + lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") initFlags (SEALED | ABSTRACT | TRAIT) + lazy val AnyValCompanionClass = getRequiredClass("scala.AnyValCompanion") initFlags (SEALED | ABSTRACT | TRAIT) // bottom types lazy val RuntimeNothingClass = getClass(fulltpnme.RuntimeNothing) @@ -202,9 +210,8 @@ trait Definitions extends reflect.api.StandardDefinitions { sealed abstract class BottomClassSymbol(name: TypeName, parent: Symbol) extends ClassSymbol(ScalaPackageClass, NoPosition, name) { locally { - this setFlag ABSTRACT | TRAIT | FINAL - this setInfo ClassInfoType(List(parent.tpe), new Scope, this) - owner.info.decls enter this + this initFlags ABSTRACT | TRAIT | FINAL + this setInfoAndEnter ClassInfoType(List(parent.tpe), new Scope, this) } final override def isBottomClass = true } @@ -296,7 +303,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // .setInfo(UnitClass.tpe) lazy val TypeConstraintClass = getRequiredClass("scala.annotation.TypeConstraint") - lazy val SingletonClass = newClass(ScalaPackageClass, tpnme.Singleton, anyparam) setFlag (ABSTRACT | TRAIT | FINAL) + lazy val SingletonClass = newClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL) lazy val SerializableClass = getRequiredClass("scala.Serializable") lazy val JavaSerializableClass = getClass(sn.JavaSerializable) lazy val ComparableClass = getRequiredClass("java.lang.Comparable") @@ -391,6 +398,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // scala.reflect lazy val ReflectApiUniverse = getRequiredClass("scala.reflect.api.Universe") + lazy val ReflectMacroContext = getRequiredClass("scala.reflect.macro.Context") lazy val ReflectRuntimeMirror = getRequiredModule("scala.reflect.runtime.Mirror") def freeValueMethod = getMember(ReflectRuntimeMirror, nme.freeValue) lazy val ReflectPackage = getPackageObject("scala.reflect") @@ -443,15 +451,11 @@ trait Definitions extends reflect.api.StandardDefinitions { def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+ def isArrowAssoc(sym: Symbol) = ArrowAssocClass.tpe.decls.toList contains sym - // The given symbol is a method with the right signature to be a runnable java program. - def isJavaMainMethod(sym: Symbol) = sym.tpe match { - case MethodType(param :: Nil, restpe) if restpe.typeSymbol == UnitClass => - param.tpe match { - case TypeRef(_, ArrayClass, arg :: Nil) => arg.typeSymbol == StringClass - case _ => false - } - case _ => false - } + // The given symbol is a method with the right name and signature to be a runnable java program. + def isJavaMainMethod(sym: Symbol) = (sym.name == nme.main) && (sym.info match { + case MethodType(p :: Nil, restpe) => isArrayOfSymbol(p.tpe, StringClass) && restpe.typeSymbol == UnitClass + case _ => false + }) // The given class has a main method. def hasJavaMainMethod(sym: Symbol): Boolean = (sym.tpe member nme.main).alternatives exists isJavaMainMethod @@ -595,6 +599,9 @@ trait Definitions extends reflect.api.StandardDefinitions { def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg)) def iteratorOfType(tp: Type) = appliedType(IteratorClass.typeConstructor, List(tp)) + lazy val StringArray = arrayType(StringClass.tpe) + lazy val ObjectArray = arrayType(ObjectClass.tpe) + def ClassType(arg: Type) = if (phase.erasedTypes || forMSIL) ClassClass.tpe else appliedType(ClassClass.typeConstructor, List(arg)) @@ -809,13 +816,6 @@ trait Definitions extends reflect.api.StandardDefinitions { */ private def getModuleOrClass(path: Name): Symbol = getModuleOrClass(path, path.length) - private def newClass(owner: Symbol, name: TypeName, parents: List[Type]): Symbol = { - val clazz = owner.newClass(NoPosition, name) - clazz.setInfo(ClassInfoType(parents, new Scope, clazz)) - owner.info.decls.enter(clazz) - clazz - } - private def newCovariantPolyClass(owner: Symbol, name: TypeName, parent: Symbol => Type): Symbol = { val clazz = newClass(owner, name, List()) val tparam = newTypeParam(clazz, 0) setFlag COVARIANT @@ -832,24 +832,8 @@ trait Definitions extends reflect.api.StandardDefinitions { ClassInfoType(List(AnyRefClass.tpe, p), new Scope, clazz))) } - private def newAlias(owner: Symbol, name: TypeName, alias: Type): Symbol = { - val tpsym = owner.newAliasType(NoPosition, name) - tpsym.setInfo(alias) - owner.info.decls.enter(tpsym) - tpsym - } - - private def newMethod(owner: Symbol, name: TermName): Symbol = { - val msym = owner.newMethod(NoPosition, name.encode) - owner.info.decls.enter(msym) - msym - } - - private[Definitions] def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type): Symbol = { - val msym = newMethod(owner, name) - val params = msym.newSyntheticValueParams(formals) - msym.setInfo(MethodType(params, restpe)) - } + private def newAlias(owner: Symbol, name: TypeName, alias: Type): Symbol = + owner.newAliasType(name) setInfoAndEnter alias /** tcon receives the type parameter symbol as argument */ private def newPolyMethod(owner: Symbol, name: TermName, tcon: Symbol => Type): Symbol = @@ -857,16 +841,14 @@ trait Definitions extends reflect.api.StandardDefinitions { /** tcon receives the type parameter symbol and the method symbol as arguments */ private def newPolyMethodCon(owner: Symbol, name: TermName, tcon: Symbol => Symbol => Type): Symbol = { - val msym = newMethod(owner, name) + val msym = owner.info.decls enter owner.newMethod(name.encode) val tparam = newTypeParam(msym, 0) - msym.setInfo(polyType(List(tparam), tcon(tparam)(msym))) - } - private def newParameterlessMethod(owner: Symbol, name: TermName, restpe: Type) = - newMethod(owner, name).setInfo(NullaryMethodType(restpe)) + msym setInfo polyType(List(tparam), tcon(tparam)(msym)) + } private def newTypeParam(owner: Symbol, index: Int): Symbol = - owner.newTypeParameter(NoPosition, newTypeName("T" + index)) setInfo TypeBounds.empty + owner.newTypeParameter(newTypeName("T" + index)) setInfo TypeBounds.empty lazy val boxedClassValues = boxedClass.values.toSet lazy val isUnbox = unboxMethod.values.toSet @@ -966,12 +948,12 @@ trait Definitions extends reflect.api.StandardDefinitions { RootClass.info.decls enter RootPackage // members of class scala.Any - Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype) setFlag FINAL - Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype) setFlag FINAL + Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) + Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) Any_equals = newMethod(AnyClass, nme.equals_, anyparam, booltype) Any_hashCode = newMethod(AnyClass, nme.hashCode_, Nil, inttype) Any_toString = newMethod(AnyClass, nme.toString_, Nil, stringtype) - Any_## = newMethod(AnyClass, nme.HASHHASH, Nil, inttype) setFlag FINAL + Any_## = newMethod(AnyClass, nme.HASHHASH, Nil, inttype, FINAL) // Any_getClass requires special handling. The return type is determined on // a per-call-site basis as if the function being called were actually: @@ -982,26 +964,24 @@ trait Definitions extends reflect.api.StandardDefinitions { // Since getClass is not actually a polymorphic method, this requires compiler // participation. At the "Any" level, the return type is Class[_] as it is in // java.lang.Object. Java also special cases the return type. - Any_getClass = ( - newMethod(AnyClass, nme.getClass_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType) - setFlag DEFERRED - ) + Any_getClass = + newMethod(AnyClass, nme.getClass_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType, DEFERRED) Any_isInstanceOf = newPolyMethod( AnyClass, nme.isInstanceOf_, tparam => NullaryMethodType(booltype)) setFlag FINAL Any_asInstanceOf = newPolyMethod( AnyClass, nme.asInstanceOf_, tparam => NullaryMethodType(tparam.typeConstructor)) setFlag FINAL // members of class java.lang.{ Object, String } - Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype) setFlag FINAL - Object_== = newMethod(ObjectClass, nme.EQ, anyrefparam, booltype) setFlag FINAL - Object_!= = newMethod(ObjectClass, nme.NE, anyrefparam, booltype) setFlag FINAL - Object_eq = newMethod(ObjectClass, nme.eq, anyrefparam, booltype) setFlag FINAL - Object_ne = newMethod(ObjectClass, nme.ne, anyrefparam, booltype) setFlag FINAL + Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL) + Object_== = newMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL) + Object_!= = newMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL) + Object_eq = newMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL) + Object_ne = newMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL) Object_synchronized = newPolyMethodCon( ObjectClass, nme.synchronized_, tparam => msym => MethodType(msym.newSyntheticValueParams(List(tparam.typeConstructor)), tparam.typeConstructor)) setFlag FINAL - String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype) setFlag FINAL + String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL) val forced = List( // force initialization of every symbol that is entered as a side effect AnnotationDefaultAttr, // #2264 @@ -1038,7 +1018,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // 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 - val newCaller = newMethod(DelegateClass, name, paramTypes, delegateType) setFlag (FINAL | STATIC) + val newCaller = newMethod(DelegateClass, name, paramTypes, delegateType, FINAL | STATIC) // val newCaller = newPolyMethod(DelegateClass, name, // tparam => MethodType(paramTypes, tparam.typeConstructor)) setFlag (FINAL | STATIC) Delegate_scalaCallers = Delegate_scalaCallers ::: List(newCaller) diff --git a/src/compiler/scala/reflect/internal/HasFlags.scala b/src/compiler/scala/reflect/internal/HasFlags.scala index 46dca0940a..ec4e919bdc 100644 --- a/src/compiler/scala/reflect/internal/HasFlags.scala +++ b/src/compiler/scala/reflect/internal/HasFlags.scala @@ -136,6 +136,9 @@ trait HasFlags { /** Whether this entity has NONE of the flags in the given mask. */ def hasNoFlags(mask: Long): Boolean = !hasFlag(mask) + + protected def isSetting(f: Long, mask: Long) = !hasFlag(f) && ((mask & f) != 0L) + protected def isClearing(f: Long, mask: Long) = hasFlag(f) && ((mask & f) != 0L) // Tests which come through cleanly: both Symbol and Modifiers use these // identically, testing for a single flag. diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index 38f808cef9..53380952c0 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -22,6 +22,7 @@ trait Importers { self: SymbolTable => val myowner = importSymbol(sym.owner) val mypos = importPosition(sym.pos) val myname = importName(sym.name).toTermName + val myflags = sym.flags def linkReferenced(mysym: TermSymbol, x: from.TermSymbol, op: from.Symbol => Symbol): Symbol = { symMap(x) = mysym mysym.referenced = op(x.referenced) @@ -29,19 +30,20 @@ trait Importers { self: SymbolTable => } val mysym = sym match { case x: from.MethodSymbol => - linkReferenced(new MethodSymbol(myowner, mypos, myname), x, importSymbol) + linkReferenced(myowner.newMethod(myname, mypos, myflags), x, importSymbol) case x: from.ModuleSymbol => - linkReferenced(new ModuleSymbol(myowner, mypos, myname), x, doImport) + linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, doImport) case x: from.FreeVar => - new FreeVar(importName(x.name).toTermName, importType(x.tpe), x.value) + newFreeVar(importName(x.name).toTermName, importType(x.tpe), x.value, myflags) case x: from.TermSymbol => - linkReferenced(new TermSymbol(myowner, mypos, myname), x, importSymbol) + linkReferenced(myowner.newValue(myname, mypos, myflags), x, importSymbol) case x: from.TypeSkolem => - new TypeSkolem(myowner, mypos, myname.toTypeName, x.unpackLocation match { - case null => null - case y: from.Tree => importTree(y) + val origin = x.unpackLocation match { + case null => null + case y: from.Tree => importTree(y) case y: from.Symbol => importSymbol(y) - }) + } + myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags) /* case x: from.ModuleClassSymbol => val mysym = new ModuleClassSymbol(myowner, mypos, myname.toTypeName) @@ -49,17 +51,17 @@ trait Importers { self: SymbolTable => mysym */ case x: from.ClassSymbol => - val mysym = new ClassSymbol(myowner, mypos, myname.toTypeName) + val mysym = myowner.newClassSymbol(myname.toTypeName, mypos, myflags) if (sym.thisSym != sym) { mysym.typeOfThis = importType(sym.typeOfThis) mysym.thisSym.name = importName(sym.thisSym.name) } mysym case x: from.TypeSymbol => - new TypeSymbol(myowner, mypos, myname.toTypeName) + myowner.newTypeSymbol(myname.toTypeName, mypos, myflags) } symMap(sym) = mysym - mysym setFlag sym.flags | Flags.LOCKED + mysym setFlag Flags.LOCKED mysym setInfo { val mytypeParams = sym.typeParams map doImport new LazyPolyType(mytypeParams) { diff --git a/src/compiler/scala/reflect/internal/NameManglers.scala b/src/compiler/scala/reflect/internal/NameManglers.scala index ef092f16bb..97a74c2383 100644 --- a/src/compiler/scala/reflect/internal/NameManglers.scala +++ b/src/compiler/scala/reflect/internal/NameManglers.scala @@ -85,7 +85,7 @@ trait NameManglers { def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX - def isImplClassName(name: Name) = stripAnonNumberSuffix(name) endsWith IMPL_CLASS_SUFFIX + def isImplClassName(name: Name) = name endsWith IMPL_CLASS_SUFFIX def isLocalDummyName(name: Name) = name startsWith LOCALDUMMY_PREFIX def isLocalName(name: Name) = name endsWith LOCAL_SUFFIX_STRING def isLoopHeaderLabel(name: Name) = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX) @@ -176,25 +176,18 @@ trait NameManglers { else name.toTermName } - /** !!! I'm putting this logic in place because I can witness - * trait impls get lifted and acquiring names like 'Foo$class$1' - * while clearly still being what they were. It's only being used on - * isImplClassName. However, it's anyone's guess how much more - * widely this logic actually ought to be applied. Anything which - * tests for how a name ends is a candidate for breaking down once - * something is lifted from a method. - * - * TODO: resolve this significant problem. - */ - def stripAnonNumberSuffix(name: Name): Name = { - val str = "" + name - if (str == "" || !str.endChar.isDigit) name - else { - val idx = name.lastPos('$') - if (idx < 0 || str.substring(idx + 1).exists(c => !c.isDigit)) name - else name.subName(0, idx) - } - } + // This isn't needed at the moment since I fixed $class$1 but + // I expect it will be at some point. + // + // def anonNumberSuffix(name: Name): Name = { + // ("" + name) lastIndexOf '$' match { + // case -1 => nme.EMPTY + // case idx => + // val s = name drop idx + // if (s.toString forall (_.isDigit)) s + // else nme.EMPTY + // } + // } def stripModuleSuffix(name: Name): Name = ( if (isModuleName(name)) name dropRight MODULE_SUFFIX_STRING.length else name diff --git a/src/compiler/scala/reflect/internal/Names.scala b/src/compiler/scala/reflect/internal/Names.scala index b960695f51..907b564d4c 100644 --- a/src/compiler/scala/reflect/internal/Names.scala +++ b/src/compiler/scala/reflect/internal/Names.scala @@ -77,7 +77,11 @@ trait Names extends api.Names { 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]. */ + /** Create a term name from the characters in cs[offset..offset+len-1]. + * TODO - have a mode where name validation is performed at creation time + * (e.g. if a name has the string "$class" in it, then fail if that + * string is not at the very end.) + */ 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) diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index ea5565c581..aba00088f9 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -13,7 +13,7 @@ import annotation.switch trait StdNames extends NameManglers { self: SymbolTable => def encode(str: String): TermName = newTermNameCached(NameTransformer.encode(str)) - + implicit def lowerTermNames(n: TermName): String = "" + n // implicit def stringToTermName(s: String): TermName = newTermName(s) @@ -182,7 +182,7 @@ trait StdNames extends NameManglers { self: SymbolTable => 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$" @@ -207,7 +207,7 @@ trait StdNames extends NameManglers { self: SymbolTable => 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" @@ -230,6 +230,31 @@ trait StdNames extends NameManglers { self: SymbolTable => val _20 : NameType = "_20" val _21 : NameType = "_21" val _22 : NameType = "_22" + + val x_0 : NameType = "x$0" + val x_1 : NameType = "x$1" + val x_2 : NameType = "x$2" + val x_3 : NameType = "x$3" + val x_4 : NameType = "x$4" + val x_5 : NameType = "x$5" + val x_6 : NameType = "x$6" + val x_7 : NameType = "x$7" + val x_8 : NameType = "x$8" + val x_9 : NameType = "x$9" + + @switch def syntheticParamName(i: Int): TermName = i match { + case 0 => nme.x_0 + case 1 => nme.x_1 + case 2 => nme.x_2 + case 3 => nme.x_3 + case 4 => nme.x_4 + case 5 => nme.x_5 + case 6 => nme.x_6 + case 7 => nme.x_7 + case 8 => nme.x_8 + case 9 => nme.x_9 + case _ => newTermName("x$" + i) + } val wrapRefArray: NameType = "wrapRefArray" val wrapByteArray: NameType = "wrapByteArray" @@ -246,6 +271,7 @@ trait StdNames extends NameManglers { self: SymbolTable => // Compiler utilized names // val productElementName: NameType = "productElementName" val Ident: NameType = "Ident" + val StringContext: NameType = "StringContext" val TYPE_ : NameType = "TYPE" val TypeTree: NameType = "TypeTree" val UNIT : NameType = "UNIT" @@ -275,6 +301,8 @@ trait StdNames extends NameManglers { self: SymbolTable => val classOf: NameType = "classOf" val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure val conforms: NameType = "conforms" + val context : NameType = "_context" + val contextImplicit : NameType = "$context" val copy: NameType = "copy" val delayedInit: NameType = "delayedInit" val delayedInitArg: NameType = "delayedInit$body" @@ -295,11 +323,9 @@ trait StdNames extends NameManglers { self: SymbolTable => 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" @@ -405,7 +431,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val REFINE_CLASS_NAME: NameType = "<refinement>" val ANON_CLASS_NAME: NameType = "$anon" } - + /** For fully qualified type names. */ object fulltpnme extends TypeNames { @@ -425,11 +451,11 @@ trait StdNames extends NameManglers { self: SymbolTable => 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" } @@ -491,7 +517,7 @@ trait StdNames extends NameManglers { self: SymbolTable => def moduleVarName(name: TermName): TermName = newTermNameCached("" + name + MODULE_VAR_SUFFIX) - + val ROOTPKG: TermName = "_root_" /** Base strings from which synthetic names are derived. */ @@ -506,7 +532,7 @@ trait StdNames extends NameManglers { self: SymbolTable => 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 @@ -543,18 +569,18 @@ trait StdNames extends NameManglers { self: SymbolTable => 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_!) + 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" @@ -645,7 +671,7 @@ trait StdNames extends NameManglers { self: SymbolTable => 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 diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 5be69e06ad..ace4d55b90 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -40,6 +40,15 @@ abstract class SymbolTable extends api.Universe def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg) def debugwarn(msg: => String): Unit = if (settings.debug.value) Console.err.println(msg) + private[scala] def printResult[T](msg: String)(result: T) = { + Console.err.println(msg + ": " + result) + result + } + private[scala] def logResult[T](msg: String)(result: T): T = { + log(msg + ": " + result) + result + } + /** Are we compiling for Java SE? */ // def forJVM: Boolean @@ -149,7 +158,7 @@ abstract class SymbolTable extends api.Universe } } // enter decls of parent classes - for (pt <- container.info.parents; p = pt.typeSymbol) { + for (p <- container.parentSymbols) { if (p != definitions.ObjectClass && p != definitions.ScalaObjectClass) { openPackageModule(p, dest) } diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 6ee061392c..a943b6fe24 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -35,6 +35,17 @@ trait Symbols extends api.Symbols { self: SymbolTable => nextexid += 1 newTypeName("_" + nextexid + suffix) } + + // Set the fields which point companions at one another. Returns the module. + def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = { + moduleClass.sourceModule = m + m setModuleClass moduleClass + m + } + /** Create a new free variable. Its owner is NoSymbol. + */ + def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar = + new FreeVar(name, value) initFlags newFlags setInfo tpe /** The original owner of a class. Used by the backend to generate * EnclosingMethod attributes. @@ -42,9 +53,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => val originalOwner = perRunCaches.newMap[Symbol, Symbol]() abstract class AbsSymbolImpl extends AbsSymbol { this: Symbol => - def newNestedSymbol(pos: Position, name: Name) = name match { - case n: TermName => newValue(pos, n) - case n: TypeName => newAliasType(pos, n) + def newNestedSymbol(name: Name, pos: Position, newFlags: Long) = name match { + case n: TermName => newTermSymbol(n, pos, newFlags) + case n: TypeName => newTypeSymbol(n, pos, newFlags) } def typeSig: Type = info def typeSigIn(site: Type): Type = site.memberInfo(this) @@ -72,7 +83,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => private var rawpos = initPos val id = { ids += 1; ids } // identity displayed when -uniqid - //assert(id != 3204, initName) var validTo: Period = NoPeriod @@ -89,64 +99,95 @@ trait Symbols extends api.Symbols { self: SymbolTable => // ------ creators ------------------------------------------------------------------- - final def newValue(pos: Position, name: TermName) = - new TermSymbol(this, pos, name) - final def newValue(name: TermName, pos: Position = NoPosition) = - new TermSymbol(this, pos, name) - final def newVariable(pos: Position, name: TermName) = - newValue(pos, name).setFlag(MUTABLE) - final def newValueParameter(pos: Position, name: TermName) = - newValue(pos, name).setFlag(PARAM) + final def newValue(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = + newTermSymbol(name, pos, newFlags) + final def newVariable(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = + newTermSymbol(name, pos, MUTABLE | newFlags) + final def newValueParameter(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = + newTermSymbol(name, pos, PARAM | newFlags) + /** Create local dummy for template (owner of local blocks) */ final def newLocalDummy(pos: Position) = - newValue(pos, nme.localDummyName(this)).setInfo(NoType) - final def newMethod(pos: Position, name: TermName) = - new MethodSymbol(this, pos, name).setFlag(METHOD) - final def newMethod(name: TermName, pos: Position = NoPosition) = - new MethodSymbol(this, pos, name).setFlag(METHOD) - final def newLabel(pos: Position, name: TermName) = - newMethod(pos, name).setFlag(LABEL) + newTermSymbol(nme.localDummyName(this), pos) setInfo NoType + final def newMethod(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): MethodSymbol = + newMethodSymbol(name, pos, METHOD | newFlags) + final def newLabel(name: TermName, pos: Position = NoPosition): MethodSymbol = + newMethod(name, pos, LABEL) /** Propagates ConstrFlags (JAVA, specifically) from owner to constructor. */ - final def newConstructor(pos: Position) = - newMethod(pos, nme.CONSTRUCTOR) setFlag getFlag(ConstrFlags) + final def newConstructor(pos: Position, newFlags: Long = 0L) = + newMethod(nme.CONSTRUCTOR, pos, getFlag(ConstrFlags) | newFlags) + /** Static constructor with info set. */ def newStaticConstructor(pos: Position) = - newConstructor(pos) setFlag STATIC setInfo UnitClass.tpe + newConstructor(pos, STATIC) setInfo UnitClass.tpe /** Instance constructor with info set. */ def newClassConstructor(pos: Position) = newConstructor(pos) setInfo MethodType(Nil, this.tpe) - private def finishModule(m: ModuleSymbol, clazz: ClassSymbol): ModuleSymbol = { - // Top-level objects can be automatically marked final, but others - // must be explicitly marked final if overridable objects are enabled. - val flags = if (isPackage || !settings.overrideObjects.value) MODULE | FINAL else MODULE - m setFlag flags - m setModuleClass clazz - m + // Top-level objects can be automatically marked final, but others + // must be explicitly marked final if overridable objects are enabled. + private def ModuleFlags = ( + if (isPackage || !settings.overrideObjects.value) MODULE | FINAL + else MODULE + ) + def newLinkedModule(clazz: Symbol, newFlags: Long = 0L): ModuleSymbol = { + val m = newModuleSymbol(clazz.name.toTermName, clazz.pos, ModuleFlags | newFlags) + connectModuleToClass(m, clazz.asInstanceOf[ClassSymbol]) + } + final def newModule(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = { + val m = newModuleSymbol(name, pos, newFlags | ModuleFlags) + val clazz = newModuleClassSymbol(name.toTypeName, pos, (m getFlag ModuleToClassFlags) | MODULE) + connectModuleToClass(m, clazz) } - private def finishModule(m: ModuleSymbol): ModuleSymbol = - finishModule(m, new ModuleClassSymbol(m)) - - final def newModule(pos: Position, name: TermName, clazz: ClassSymbol): ModuleSymbol = - finishModule(new ModuleSymbol(this, pos, name), clazz) - - final def newModule(name: TermName, clazz: Symbol, pos: Position = NoPosition): ModuleSymbol = - newModule(pos, name, clazz.asInstanceOf[ClassSymbol]) - - final def newModule(pos: Position, name: TermName): ModuleSymbol = - finishModule(new ModuleSymbol(this, pos, name)) - final def newPackage(pos: Position, name: TermName): ModuleSymbol = { - assert(name == nme.ROOT || isPackageClass) - val m = newModule(pos, name).setFlag(JAVA | PACKAGE) - m.moduleClass setFlag (JAVA | PACKAGE) - m + final def newPackage(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = { + assert(name == nme.ROOT || isPackageClass, this) + newModule(name, pos, JAVA | PACKAGE | newFlags) } final def newThisSym(pos: Position) = - newValue(pos, nme.this_).setFlag(SYNTHETIC) + newTermSymbol(nme.this_, pos, SYNTHETIC) final def newImport(pos: Position) = - newValue(pos, nme.IMPORT) + newTermSymbol(nme.IMPORT, pos) + + /** Direct symbol factories. + * For internal use; these are unlikely to be what you want. + */ + def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = + new TermSymbol(this, pos, name) initFlags newFlags + + def newAbstractTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol = + new AbstractTypeSymbol(this, pos, name) initFlags newFlags + + def newAliasTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol = + new AliasTypeSymbol(this, pos, name) initFlags newFlags + + def newModuleSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = + new ModuleSymbol(this, pos, name) initFlags newFlags + + def newMethodSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): MethodSymbol = + new MethodSymbol(this, pos, name) initFlags newFlags + + def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = + new ClassSymbol(this, pos, name) initFlags newFlags + + def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol = + new ModuleClassSymbol(this, pos, name) initFlags newFlags + + /** Derive whether it is an abstract type from the flags; after creation + * the DEFERRED flag will be ignored. + */ + def newTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol = + if ((newFlags & DEFERRED) == 0L) + newAliasTypeSymbol(name, pos, newFlags) + else + newAbstractTypeSymbol(name, pos, newFlags) + + def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem = + if ((newFlags & DEFERRED) == 0L) + new TypeSkolem(this, pos, name, origin) initFlags newFlags + else + new TypeSkolem(this, pos, name, origin) with AbstractTypeMixin initFlags newFlags /** @param pre type relative to which alternatives are seen. * for instance: @@ -166,58 +207,50 @@ trait Symbols extends api.Symbols { self: SymbolTable => * * pre.memberType(m) */ - final def newOverloaded(pre: Type, alternatives: List[Symbol]): Symbol = - newValue(alternatives.head.pos, alternatives.head.name.toTermName) - .setFlag(OVERLOADED) - .setInfo(OverloadedType(pre, alternatives)) - - /** for explicit outer phase */ - final def newOuterAccessor(pos: Position) = { - val sym = newMethod(pos, nme.OUTER) - sym setFlag (STABLE | SYNTHETIC) - if (isTrait) sym setFlag DEFERRED - sym.expandName(this) - sym.referenced = this - sym - } + final def newOverloaded(pre: Type, alternatives: List[Symbol]): Symbol = ( + newTermSymbol(alternatives.head.name.toTermName, alternatives.head.pos, OVERLOADED) + setInfo OverloadedType(pre, alternatives) + ) final def newErrorValue(name: TermName) = - newValue(pos, name).setFlag(SYNTHETIC | IS_ERROR).setInfo(ErrorType) + newTermSymbol(name, pos, SYNTHETIC | IS_ERROR) setInfo ErrorType /** Symbol of a type definition type T = ... */ - final def newAliasType(pos: Position, name: TypeName) = - new TypeSymbol(this, pos, name) - final def newAliasType(name: TypeName, pos: Position = NoPosition) = - new TypeSymbol(this, pos, name) - + final def newAliasType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = + newAliasTypeSymbol(name, pos, newFlags) + /** Symbol of an abstract type type T >: ... <: ... */ - final def newAbstractType(pos: Position, name: TypeName) = - new TypeSymbol(this, pos, name).setFlag(DEFERRED) - final def newAbstractType(name: TypeName, pos: Position = NoPosition) = - new TypeSymbol(this, pos, name).setFlag(DEFERRED) + final def newAbstractType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = + newAbstractTypeSymbol(name, pos, DEFERRED | newFlags) /** Symbol of a type parameter */ - final def newTypeParameter(pos: Position, name: TypeName) = - newAbstractType(pos, name).setFlag(PARAM) + final def newTypeParameter(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L) = + newAbstractType(name, pos, PARAM | newFlags) /** Synthetic value parameters when parameter symbols are not available */ final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[Symbol]] = { var cnt = 0 - def freshName() = { cnt += 1; newTermName("x$" + cnt) } - def param(tp: Type) = - newValueParameter(focusPos(owner.pos), freshName()).setFlag(SYNTHETIC).setInfo(tp) - argtypess map (_.map(param)) + def freshName() = { cnt += 1; nme.syntheticParamName(cnt) } + mmap(argtypess)(tp => newValueParameter(freshName(), focusPos(owner.pos), SYNTHETIC) setInfo tp) } - final def newExistential(pos: Position, name: TypeName): Symbol = - newAbstractType(pos, name).setFlag(EXISTENTIAL) + /** Create a new existential type skolem with this symbol its owner, + * based on the given symbol and origin. + */ + def newExistentialSkolem(basis: Symbol, origin: AnyRef): TypeSkolem = { + val skolem = newTypeSkolemSymbol(basis.name.toTypeName, origin, basis.pos, (basis.flags | EXISTENTIAL) & ~PARAM) + skolem setInfo (basis.info cloneInfo skolem) + } + + final def newExistential(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = + newAbstractType(name, pos, EXISTENTIAL | newFlags) final def freshExistential(suffix: String): Symbol = - newExistential(pos, freshExistentialName(suffix)) + newExistential(freshExistentialName(suffix), pos) /** Synthetic value parameters when parameter symbols are not available. * Calling this method multiple times will re-use the same parameter names. @@ -237,52 +270,67 @@ trait Symbols extends api.Symbols { self: SymbolTable => * body of the method, there's a local copy of `T` which is a TypeSkolem. */ final def newTypeSkolem: Symbol = - new TypeSkolem(owner, pos, name.toTypeName, this) - .setFlag(flags) + owner.newTypeSkolemSymbol(name.toTypeName, this, pos, flags) - final def newClass(pos: Position, name: TypeName) = - new ClassSymbol(this, pos, name) - final def newClass(name: TypeName, pos: Position = NoPosition) = - new ClassSymbol(this, pos, name) + final def newClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L) = + newClassSymbol(name, pos, newFlags) + + /** A new class with its info set to a ClassInfoType with given scope and parents. */ + def newClassWithInfo(name: TypeName, parents: List[Type], scope: Scope, pos: Position = NoPosition, newFlags: Long = 0L) = { + val clazz = newClass(name, pos, newFlags) + clazz setInfo ClassInfoType(parents, scope, clazz) + } + final def newErrorClass(name: TypeName) = + newClassWithInfo(name, Nil, new ErrorScope(this), pos, SYNTHETIC | IS_ERROR) - final def newModuleClass(pos: Position, name: TypeName) = - new ModuleClassSymbol(this, pos, name) final def newModuleClass(name: TypeName, pos: Position = NoPosition) = - new ModuleClassSymbol(this, pos, name) + newModuleClassSymbol(name, pos) final def newAnonymousClass(pos: Position) = - newClass(pos, tpnme.ANON_CLASS_NAME) - final def newAnonymousFunctionClass(pos: Position) = - newClass(pos, tpnme.ANON_FUN_NAME) + newClassSymbol(tpnme.ANON_CLASS_NAME, pos) + + final def newAnonymousFunctionClass(pos: Position, newFlags: Long = 0L) = + newClassSymbol(tpnme.ANON_FUN_NAME, pos, FINAL | SYNTHETIC | newFlags) + + final def newAnonymousFunctionValue(pos: Position, newFlags: Long = 0L) = + newTermSymbol(nme.ANON_FUN_NAME, pos, SYNTHETIC | newFlags) setInfo NoType /** Refinement types P { val x: String; type T <: Number } * also have symbols, they are refinementClasses */ final def newRefinementClass(pos: Position) = - newClass(pos, tpnme.REFINE_CLASS_NAME) + newClass(tpnme.REFINE_CLASS_NAME, pos) /** Create a new getter for current symbol (which must be a field) */ final def newGetter: Symbol = ( - owner.newMethod(focusPos(pos), nme.getterName(name.toTermName)) - setFlag getterFlags(flags) + owner.newMethod(nme.getterName(name.toTermName), NoPosition, getterFlags(flags)) setPrivateWithin privateWithin setInfo MethodType(Nil, tpe) ) - final def newErrorClass(name: TypeName) = { - val clazz = newClass(pos, name) - ( clazz - setFlag (SYNTHETIC | IS_ERROR) - setInfo ClassInfoType(Nil, new ErrorScope(this), clazz) - ) - } - final def newErrorSymbol(name: Name): Symbol = name match { case x: TypeName => newErrorClass(x) case x: TermName => newErrorValue(x) } + @deprecated("Use the other signature", "2.10.0") + def newClass(pos: Position, name: TypeName): Symbol = newClass(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newModuleClass(pos: Position, name: TypeName): Symbol = newModuleClass(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newLabel(pos: Position, name: TermName): MethodSymbol = newLabel(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newValue(pos: Position, name: TermName): TermSymbol = newTermSymbol(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newAliasType(pos: Position, name: TypeName): Symbol = newAliasType(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newAbstractType(pos: Position, name: TypeName): Symbol = newAbstractType(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newExistential(pos: Position, name: TypeName): Symbol = newExistential(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newMethod(pos: Position, name: TermName): MethodSymbol = newMethod(name, pos) + // ----- locking and unlocking ------------------------------------------------------ // True if the symbol is unlocked. @@ -424,9 +472,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isAnonOrRefinementClass = isAnonymousClass || isRefinementClass // A package object or its module class - final def isPackageObjectOrClass = name == nme.PACKAGE || name == tpnme.PACKAGE - final def isPackageObject = name == nme.PACKAGE && owner.isPackageClass - final def isPackageObjectClass = name == tpnme.PACKAGE && owner.isPackageClass + final def isPackageObjectOrClass = (this ne NoSymbol) && owner.isPackageClass && (name == nme.PACKAGE || name == tpnme.PACKAGE) + final def isPackageObject = (this ne NoSymbol) && owner.isPackageClass && name == nme.PACKAGE + final def isPackageObjectClass = (this ne NoSymbol) && owner.isPackageClass && name == tpnme.PACKAGE final def isDefinedInPackage = effectiveOwner.isPackageClass final def isJavaInterface = isJavaDefined && isTrait @@ -437,7 +485,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** The owner, skipping package objects. */ - def effectiveOwner = owner.skipPackageObject + def effectiveOwner = if (owner.isPackageObjectClass) owner.skipPackageObject else owner /** If this is a package object or its implementing class, its owner: otherwise this. */ @@ -808,8 +856,17 @@ trait Symbols extends api.Symbols { self: SymbolTable => (fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift) } final def flags_=(fs: Long) = rawflags = fs - final def setFlag(mask: Long): this.type = { rawflags = rawflags | mask; this } - final def resetFlag(mask: Long): this.type = { rawflags = rawflags & ~mask; this } + + /** Set the symbol's flags to the given value, asserting + * that the previous value was 0. + */ + def initFlags(mask: Long): this.type = { + assert(rawflags == 0L, this) + rawflags = mask + this + } + def setFlag(mask: Long): this.type = { rawflags = rawflags | mask ; this } + def resetFlag(mask: Long): this.type = { rawflags = rawflags & ~mask ; this } final def getFlag(mask: Long): Long = flags & mask final def resetFlags() { rawflags = rawflags & TopLevelCreationFlags } @@ -937,6 +994,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Substitute second list of symbols for first in current info. */ def substInfo(syms0: List[Symbol], syms1: List[Symbol]) = modifyInfo(_.substSym(syms0, syms1)) def setInfoOwnerAdjusted(info: Type): this.type = setInfo(info atOwner this) + + /** Set the info and enter this symbol into the owner's scope. */ + def setInfoAndEnter(info: Type): this.type = { + setInfo(info) + owner.info.decls enter this + this + } /** Set new info valid from start of this phase. */ final def updateInfo(info: Type): Symbol = { @@ -1124,7 +1188,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => oldsymbuf += sym newsymbuf += ( if (sym.isClass) - tp.typeSymbol.newAbstractType(sym.pos, sym.name.toTypeName).setInfo(sym.existentialBound) + tp.typeSymbol.newAbstractType(sym.name.toTypeName, sym.pos).setInfo(sym.existentialBound) else sym.cloneSymbol(tp.typeSymbol)) } @@ -1141,15 +1205,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * the bound of the type variable that stands for it * pre: symbol is a term, a class, or an abstract type (no alias type allowed) */ - def existentialBound: Type = - if (this.isClass) - polyType(this.typeParams, TypeBounds.upper(this.classBound)) - else if (this.isAbstractType) - this.info - else if (this.isTerm) - singletonBounds(this.tpe) - else - abort("unexpected alias type: "+this) + def existentialBound: Type /** Reset symbol to initial state */ @@ -1282,18 +1338,18 @@ trait Symbols extends api.Symbols { self: SymbolTable => cloneSymbol(owner) /** A clone of this symbol, but with given owner. */ - final def cloneSymbol(owner: Symbol): Symbol = { - val newSym = cloneSymbolImpl(owner) + final def cloneSymbol(owner: Symbol): Symbol = cloneSymbol(owner, this.rawflags) + final def cloneSymbol(owner: Symbol, newFlags: Long): Symbol = { + val newSym = cloneSymbolImpl(owner, newFlags) ( newSym setPrivateWithin privateWithin setInfo (info cloneInfo newSym) - setFlag this.rawflags setAnnotations this.annotations ) } - - /** Internal method to clone a symbol's implementation without flags or type. */ - def cloneSymbolImpl(owner: Symbol): Symbol + /** Internal method to clone a symbol's implementation with the given flags and no info. */ + def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol + def cloneSymbolImpl(owner: Symbol): Symbol = cloneSymbolImpl(owner, 0L) // ------ access to related symbols -------------------------------------------------- @@ -1369,7 +1425,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def sourceModule: Symbol = NoSymbol - /** The implementation class of a trait. */ + /** The implementation class of a trait. If available it will be the + * symbol with the same owner, and the name of this symbol with $class + * appended to it. + */ final def implClass: Symbol = owner.info.decl(nme.implClassName(name)) /** The class that is logically an outer class of given `clazz`. @@ -1402,6 +1461,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** The superclass of this class. */ def superClass: Symbol = if (info.parents.isEmpty) NoSymbol else info.parents.head.typeSymbol + def parentSymbols: List[Symbol] = info.parents map (_.typeSymbol) /** The directly or indirectly inherited mixins of this class * except for mixin classes inherited by the superclass. Mixin classes appear @@ -1997,9 +2057,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => privateWithin = NoSymbol var referenced: Symbol = NoSymbol + + def existentialBound = singletonBounds(this.tpe) - def cloneSymbolImpl(owner: Symbol): Symbol = - new TermSymbol(owner, pos, name).copyAttrsFrom(this) + def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = + owner.newTermSymbol(name, pos, newFlags).copyAttrsFrom(this) def copyAttrsFrom(original: TermSymbol): this.type = { referenced = original.referenced @@ -2029,13 +2091,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (hasFlag(MODULE)) referenced else NoSymbol def setModuleClass(clazz: Symbol): TermSymbol = { - assert(hasFlag(MODULE)) + assert(hasFlag(MODULE), this) referenced = clazz this } def setLazyAccessor(sym: Symbol): TermSymbol = { - assert(isLazy && (referenced == NoSymbol || referenced == sym), this) + assert(isLazy && (referenced == NoSymbol || referenced == sym), (this, hasFlagsToString(-1L), referenced, sym)) referenced = sym this } @@ -2095,8 +2157,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => else rawname.toTermName ) - override def cloneSymbolImpl(owner: Symbol): Symbol = - new ModuleSymbol(owner, pos, name).copyAttrsFrom(this) + override def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = + owner.newModuleSymbol(name, pos, newFlags).copyAttrsFrom(this) } /** A class for method symbols */ @@ -2107,8 +2169,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => private var mtpeResult: Type = _ private var mtpeInfo: Type = _ - override def cloneSymbolImpl(owner: Symbol): Symbol = - new MethodSymbol(owner, pos, name).copyAttrsFrom(this) + override def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = + owner.newMethodSymbol(name, pos, newFlags).copyAttrsFrom(this) def typeAsMemberOf(pre: Type): Type = { if (mtpePeriod == currentPeriod) { @@ -2125,24 +2187,71 @@ trait Symbols extends api.Symbols { self: SymbolTable => res } } + + class AliasTypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) + extends TypeSymbol(initOwner, initPos, initName) { + // Temporary programmatic help tracking down who might do such a thing + override def setFlag(mask: Long): this.type = { + if (isSetting(DEFERRED, mask)) { + println("Setting DEFERRED on alias at") + (new Throwable).printStackTrace + } + super.setFlag(mask) + } + final override def isAliasType = true + override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AliasTypeSymbol = + owner.newAliasTypeSymbol(name, pos, newFlags) + } + + class AbstractTypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) + extends TypeSymbol(initOwner, initPos, initName) with AbstractTypeMixin { + override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AbstractTypeSymbol = + owner.newAbstractTypeSymbol(name, pos, newFlags) + } + + /** Might be mixed into TypeSymbol or TypeSkolem. + */ + trait AbstractTypeMixin extends TypeSymbol { + override def resetFlag(mask: Long): this.type = { + // Temporary programmatic help tracking down who might do such a thing + if (settings.debug.value) { + if (isClearing(DEFERRED, mask)) { + println("Clearing DEFERRED on abstract type at") + (new Throwable).printStackTrace + } + } + super.resetFlag(mask) + } + final override def isAbstractType = true + override def existentialBound = this.info + } /** A class of type symbols. Alias and abstract types are direct instances * of this class. Classes are instances of a subclass. */ - class TypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) - extends Symbol(initOwner, initPos, initName) { + sealed abstract class TypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) extends Symbol(initOwner, initPos, initName) { privateWithin = NoSymbol private var tyconCache: Type = null private var tyconRunId = NoRunId private var tpeCache: Type = _ private var tpePeriod = NoPeriod + /** Overridden in subclasses for which it makes sense. + */ + def existentialBound: Type = abort("unexpected type: "+this.getClass+ " "+this.fullLocationString+ " " + hasFlagsToString(-1L)) + override def name: TypeName = super.name.asInstanceOf[TypeName] final override def isType = true override def isNonClassType = true - override def isAbstractType = isDeferred - override def isAliasType = !isDeferred - + override def isAbstractType = { + if (settings.debug.value) { + if (isDeferred) { + println("TypeSymbol claims to be abstract type: " + this.getClass + " " + hasFlagsToString(-1L) + " at ") + (new Throwable).printStackTrace + } + } + isDeferred + } private def newTypeRef(targs: List[Type]) = { val pre = if (hasFlag(PARAM | EXISTENTIAL)) NoPrefix else owner.thisType typeRef(pre, this, targs) @@ -2198,9 +2307,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ override def tpeHK = typeConstructor // @M! used in memberType - // needed for experimental code for early types as type parameters - // def refreshType() { tpePeriod = NoPeriod } - override def typeConstructor: Type = { if ((tyconCache eq null) || tyconRunId != currentRunId) { tyconCache = newTypeRef(Nil) @@ -2242,8 +2348,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => } } - def cloneSymbolImpl(owner: Symbol): Symbol = - new TypeSymbol(owner, pos, name) + def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = + owner.newTypeSymbol(name, pos, newFlags) incCounter(typeSymbolCount) } @@ -2281,8 +2387,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => //@M! (not deSkolemize.typeParams!!), also can't leave superclass definition: use info, not rawInfo override def typeParams = info.typeParams - override def cloneSymbolImpl(owner: Symbol): Symbol = - new TypeSkolem(owner, pos, name, origin) + override def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = + owner.newTypeSkolemSymbol(name, origin, pos, newFlags) override def nameString: String = if (settings.debug.value) (super.nameString + "&" + level) @@ -2300,6 +2406,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => final override def isNonClassType = false final override def isAbstractType = false final override def isAliasType = false + + override def existentialBound = polyType(this.typeParams, TypeBounds.upper(this.classBound)) override def sourceFile = if (owner.isPackageClass) source @@ -2362,8 +2470,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => thissym = newThisSym(pos).setInfo(tp) } - override def cloneSymbolImpl(owner: Symbol): Symbol = { - val clone = new ClassSymbol(owner, pos, name) + override def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = { + val clone = owner.newClassSymbol(name, pos, newFlags) if (thisSym != this) { clone.typeOfThis = typeOfThis clone.thisSym.name = thisSym.name @@ -2388,35 +2496,32 @@ trait Symbols extends api.Symbols { self: SymbolTable => class ModuleClassSymbol(owner: Symbol, pos: Position, name: TypeName) extends ClassSymbol(owner, pos, name) { private var module: Symbol = null - def this(module: TermSymbol) = { - this(module.owner, module.pos, module.name.toTypeName) - setFlag(module.getFlag(ModuleToClassFlags) | MODULE) - sourceModule = module - } - override def sourceModule = module private var implicitMembersCacheValue: List[Symbol] = List() private var implicitMembersCacheKey1: Type = NoType private var implicitMembersCacheKey2: ScopeEntry = null + def implicitMembers: List[Symbol] = { val tp = info if ((implicitMembersCacheKey1 ne tp) || (implicitMembersCacheKey2 ne tp.decls.elems)) { - implicitMembersCacheKey1 = tp - implicitMembersCacheKey2 = tp.decls.elems - implicitMembersCacheValue = tp.implicitMembers + // Skip a package object class, because the members are also in + // the package and we wish to avoid spurious ambiguities as in pos/t3999. + if (!isPackageObjectClass) { + implicitMembersCacheKey1 = tp + implicitMembersCacheKey2 = tp.decls.elems + implicitMembersCacheValue = tp.implicitMembers + } } implicitMembersCacheValue } + override def sourceModule = module override def sourceModule_=(module: Symbol) { this.module = module } } - class FreeVar(name0: TermName, tpe: Type, val value: Any) extends TermSymbol(definitions.RootClass, NoPosition, name0) { - setInfo(tpe) - + class FreeVar(name0: TermName, val value: Any) extends TermSymbol(NoSymbol, NoPosition, name0) { override def hashCode = value.hashCode - override def equals(other: Any): Boolean = other match { case that: FreeVar => this.value.asInstanceOf[AnyRef] eq that.value.asInstanceOf[AnyRef] - case _ => false + case _ => false } } @@ -2436,18 +2541,23 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def enclClass: Symbol = this override def toplevelClass: Symbol = this override def enclMethod: Symbol = this - override def owner: Symbol = abort("no-symbol does not have owner") override def sourceFile: AbstractFileType = null override def ownerChain: List[Symbol] = List() override def ownersIterator: Iterator[Symbol] = Iterator.empty override def alternatives: List[Symbol] = List() override def reset(completer: Type) {} override def info: Type = NoType + override def existentialBound: Type = NoType override def rawInfo: Type = NoType protected def doCookJavaRawInfo() {} override def accessBoundary(base: Symbol): Symbol = RootClass - def cloneSymbolImpl(owner: Symbol): Symbol = abort() + def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = abort() override def originalEnclosingMethod = this + + override def owner: Symbol = + abort("no-symbol does not have an owner (this is a bug: scala " + scala.util.Properties.versionString + ")") + override def typeConstructor: Type = + abort("no-symbol does not have a type constructor (this may indicate scalac cannot find fundamental classes)") } /** Derives a new list of symbols from the given list by mapping the given @@ -2518,17 +2628,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ 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. - */ - def newExistentialSkolem(sym: Symbol, owner: Symbol, origin: AnyRef): TypeSkolem = { - val skolem = new TypeSkolem(owner, sym.pos, sym.name.toTypeName, origin) - ( skolem - setInfo (sym.info cloneInfo skolem) - setFlag (sym.flags | EXISTENTIAL) - resetFlag PARAM - ) - } - /** An exception for cyclic references of symbol definitions */ case class CyclicReference(sym: Symbol, info: Type) extends TypeError("illegal cyclic reference involving " + sym) { diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 96f2c5cc45..a2c55a89d6 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -121,7 +121,12 @@ trait Trees extends api.Trees { self: SymbolTable => new ChangeOwnerTraverser(oldOwner, newOwner) apply t } } - + + def substTreeSyms(pairs: (Symbol, Symbol)*): Tree = { + val list = pairs.toList + val subst = new TreeSymSubstituter(list map (_._1), list map (_._2)) + subst(tree) + } def shallowDuplicate: Tree = new ShallowDuplicator(tree) transform tree def shortClass: String = tree.getClass.getName split "[.$]" last /** When you want to know a little more than the class, but a lot @@ -198,9 +203,8 @@ trait Trees extends api.Trees { self: SymbolTable => def DefDef(sym: Symbol, rhs: Tree): DefDef = DefDef(sym, Modifiers(sym.flags), rhs) - def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = { + def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = DefDef(sym, rhs(sym.info.paramss)) - } /** A TypeDef node which defines given `sym` with given tight hand side `rhs`. */ def TypeDef(sym: Symbol, rhs: Tree): TypeDef = diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 4630733db4..1df60f32d9 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -322,13 +322,20 @@ trait Types extends api.Types { self: SymbolTable => /** The type symbol associated with the type * Note that the symbol of the normalized type is returned (@see normalize) + * A type's typeSymbol should if possible not be inspected directly, due to + * the likelihood that what is true for tp.typeSymbol is not true for + * tp.sym, due to normalization. */ def typeSymbol: Symbol = NoSymbol - /** The term symbol ''directly'' associated with the type. */ + /** The term symbol ''directly'' associated with the type. + */ def termSymbolDirect: Symbol = termSymbol - /** The type symbol ''directly'' associated with the type. */ + /** The type symbol ''directly'' associated with the type. + * In other words, no normalization is performed: if this is an alias type, + * the symbol returned is that of the alias, not the underlying type. + */ def typeSymbolDirect: Symbol = typeSymbol /** The base type underlying a type proxy, identity on all other types */ @@ -412,6 +419,11 @@ trait Types extends api.Types { self: SymbolTable => /** For a typeref, its arguments. The empty list for all other types */ def typeArgs: List[Type] = List() + + /** A list of placeholder types derived from the type parameters. + * Used by RefinedType and TypeRef. + */ + protected def dummyArgs: List[Type] = typeParams map (_.typeConstructor) /** For a (nullary) method or poly type, its direct result type, * the type itself for all other types. */ @@ -931,30 +943,12 @@ trait Types extends api.Types { self: SymbolTable => */ //TODO: use narrow only for modules? (correct? efficiency gain?) def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = { - var suspension: mutable.HashSet[TypeVar] = null // if this type contains type variables, put them to sleep for a while -- don't just wipe them out by // replacing them by the corresponding type parameter, as that messes up (e.g.) type variables in type refinements // without this, the matchesType call would lead to type variables on both sides // of a subtyping/equality judgement, which can lead to recursive types being constructed. // See (t0851) for a situation where this happens. - if (!this.isGround) { - // PP: The foreach below was formerly expressed as: - // for(tv @ TypeVar(_, _) <- this) { suspension suspend tv } - // - // The tree checker failed this saying a TypeVar is required, but a (Type @unchecked) was found. - // This is a consequence of using a pattern match and variable binding + ticket #1503, which - // was addressed by weakening the type of bindings in pattern matches if they occur on the right. - // So I'm not quite sure why this works at all, as the checker is right that it is mistyped. - // For now I modified it as below, which achieves the same without error. - // - // make each type var in this type use its original type for comparisons instead of collecting constraints - val susp = new mutable.HashSet[TypeVar] // use a local val so it remains unboxed - this foreach { - case tv: TypeVar => tv.suspended = true; susp += tv - case _ => - } - suspension = susp - } + val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this) incCounter(findMemberCount) val start = startTimer(findMemberNanos) @@ -1504,8 +1498,6 @@ trait Types extends api.Types { self: SymbolTable => override def typeConstructor = copyRefinedType(this, parents map (_.typeConstructor), decls) - private def dummyArgs = typeParams map (_.typeConstructor) - /* MO to AM: This is probably not correct * If they are several higher-kinded parents with different bounds we need * to take the intersection of their bounds @@ -1650,11 +1642,12 @@ trait Types extends api.Types { self: SymbolTable => def apply(tp: Type): Type = { tp match { - case TypeRef(_, sym, args) if args.nonEmpty => - if (settings.debug.value && !sameLength(sym.info.typeParams, args)) + case tr @ TypeRef(_, sym, args) if args.nonEmpty => + val tparams = tr.initializedTypeParams + if (settings.debug.value && !sameLength(tparams, args)) debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + args) - foreach2(sym.info.typeParams, args) { (tparam1, arg) => + foreach2(tparams, args) { (tparam1, arg) => if (arg contains tparam) { addRef(NonExpansive, tparam, tparam1) if (arg.typeSymbol != tparam) @@ -1759,134 +1752,282 @@ trait Types extends api.Types { self: SymbolTable => private var volatileRecursions: Int = 0 private val pendingVolatiles = new mutable.HashSet[Symbol] + + class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) with UniqueType { + require(args0.nonEmpty, this) - /** A class for named types of the form - * `<prefix>.<sym.name>[args]` - * Cannot be created directly; one should always use `typeRef` - * for creation. (@M: Otherwise hashing breaks) - * - * @M: a higher-kinded type is represented as a TypeRef with sym.info.typeParams.nonEmpty, but args.isEmpty - * @param pre ... - * @param sym ... - * @param args ... - */ - abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type { -// assert(!sym.isAbstractType || pre.isStable || pre.isError) -// assert(!pre.isInstanceOf[ClassInfoType], this) -// assert(!(sym hasFlag (PARAM | EXISTENTIAL)) || pre == NoPrefix, this) -// assert(args.isEmpty || !sym.info.typeParams.isEmpty, this) -// assert(args.isEmpty || ((sym ne AnyClass) && (sym ne NothingClass)) + /** No unapplied type params size it has (should have) equally as many args. */ + override def isHigherKinded = false + override def typeParams = Nil - private var parentsCache: List[Type] = _ - private var parentsPeriod = NoPeriod + override def transform(tp: Type): Type = { + // This situation arises when a typevar is encountered for which + // too little information is known to determine its kind, and + // it later turns out not to have kind *. See SI-4070. Only + // logging it for now. + if (sym.typeParams.size != args.size) + log("!!! %s.transform(%s), but tparams.isEmpty and args=".format(this, tp, args)) - private var baseTypeSeqCache: BaseTypeSeq = _ - private var baseTypeSeqPeriod = NoPeriod + asSeenFromOwner(tp).instantiateTypeParams(sym.typeParams, args) + } + + // 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) + } + class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) with UniqueType { + // A reference (in a Scala program) to a type that has type parameters, but where the reference + // does not include type arguments. Note that it doesn't matter whether the symbol refers + // to a java or scala symbol, but it does matter whether it occurs in java or scala code. + // TypeRefs w/o type params that occur in java signatures/code are considered raw types, and are + // represented as existential types. + override def isHigherKinded = typeParams.nonEmpty + override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams + private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym) + + override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = + if (isHigherKinded) { + if (sameLength(formals intersect typeParams, typeParams)) + copyTypeRef(this, pre, sym, actuals) + // partial application (needed in infer when bunching type arguments from classes and methods together) + else + copyTypeRef(this, pre, sym, dummyArgs).instantiateTypeParams(formals, actuals) + } + else + super.instantiateTypeParams(formals, actuals) - private var symInfoCache: Type = _ - private var memberInfoCache: Type = _ - private var thisInfoCache: Type = _ - private var relativeInfoCache: Type = _ + override def transform(tp: Type): Type = { + val res = asSeenFromOwner(tp) + if (isHigherKinded && !isRaw) + res.instantiateTypeParams(typeParams, dummyArgs) + else + res + } - private var normalized: Type = null + override def transformInfo(tp: Type): Type = + appliedType(asSeenFromOwner(tp), dummyArgs) + + override def narrow = + if (sym.isModuleClass) singleType(pre, sym.sourceModule) + else super.narrow - override def isStable: Boolean = { - sym == NothingClass || - sym == SingletonClass || - sym.isAliasType && normalize.isStable || - sym.isAbstractType && (bounds.hi.typeSymbol isSubClass SingletonClass) - } + override def typeConstructor = this + // eta-expand, subtyping relies on eta-expansion of higher-kinded types - override def isVolatile: Boolean = { - sym.isAliasType && normalize.isVolatile || - sym.isAbstractType && { - // need to be careful not to fall into an infinite recursion here - // because volatile checking is done before all cycles are detected. - // the case to avoid is an abstract type directly or - // indirectly upper-bounded by itself. See #2918 - try { - volatileRecursions += 1 - if (volatileRecursions < LogVolatileThreshold) - bounds.hi.isVolatile - else if (pendingVolatiles(sym)) - true // we can return true here, because a cycle will be detected - // here afterwards and an error will result anyway. - else - try { - pendingVolatiles += sym - bounds.hi.isVolatile - } finally { - pendingVolatiles -= sym - } - } finally { - volatileRecursions -= 1 - } - } - } + override protected def normalizeImpl: Type = + if (isHigherKinded) etaExpand else super.normalizeImpl + } + + trait ClassTypeRef extends TypeRef { + // !!! There are scaladoc-created symbols arriving which violate this require. + // require(sym.isClass, sym) + + override protected def normalizeImpl: Type = + if (sym.isRefinementClass) sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers + else super.normalizeImpl - override lazy val isTrivial: Boolean = - !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial) + override def baseType(clazz: Symbol): Type = + if (sym == clazz) this + else transform(sym.info.baseType(clazz)) + } + trait NonClassTypeRef extends TypeRef { + require(sym.isNonClassType, sym) - override def isNotNull = - sym.isModuleClass || sym == NothingClass || isValueClass(sym) || super.isNotNull + private var relativeInfoCache: Type = _ + private var memberInfoCache: Type = _ - // @M: propagate actual type params (args) to `tp`, by replacing formal type parameters with actual ones - // if tp is higher kinded, the "actual" type arguments are types that simply reference the corresponding type parameters (unbound type variables) - def transform(tp: Type): Type = { - val res = tp.asSeenFrom(pre, sym.owner) - if (sym.typeParams.isEmpty || (args exists (_.isError)) || isRaw(sym, args)/*#2266/2305*/) res - else res.instantiateTypeParams(sym.typeParams, typeArgsOrDummies) + private def relativeInfo = { + val memberInfo = pre.memberInfo(sym) + if (relativeInfoCache == null || (memberInfo ne memberInfoCache)) { + memberInfoCache = memberInfo + relativeInfoCache = transformInfo(memberInfo) + } + relativeInfoCache } + + override def baseType(clazz: Symbol): Type = ( + if (sym == clazz) this else try { + basetypeRecursions += 1 + if (basetypeRecursions < LogPendingBaseTypesThreshold) + relativeInfo.baseType(clazz) + else if (pendingBaseTypes contains this) + if (clazz == AnyClass) clazz.tpe else NoType + else + try { + pendingBaseTypes += this + relativeInfo.baseType(clazz) + } finally { + pendingBaseTypes -= this + } + } finally { + basetypeRecursions -= 1 + } + ) + } + trait AliasTypeRef extends NonClassTypeRef { + require(sym.isAliasType, sym) + + override def dealias = if (typeParamsMatchArgs) betaReduce.dealias else super.dealias + override def isStable = normalize.isStable + override def isVolatile = normalize.isVolatile + override def narrow = normalize.narrow + override def thisInfo = normalize + override def prefix = if (this ne normalize) normalize.prefix else pre + override def termSymbol = if (this ne normalize) normalize.termSymbol else super.termSymbol + override def typeSymbol = if (this ne normalize) normalize.typeSymbol else sym + + // beta-reduce, but don't do partial application -- cycles have been checked in typeRef + override protected def normalizeImpl = + if (typeParamsMatchArgs) betaReduce.normalize + else if (isHigherKinded) super.normalizeImpl + else ErrorType + + // isHKSubType0 introduces synthetic type params so that + // betaReduce can first apply sym.info to typeArgs before calling + // asSeenFrom. asSeenFrom then skips synthetic type params, which + // are used to reduce HO subtyping to first-order subtyping, but + // which can't be instantiated from the given prefix and class. + // + // this crashes pos/depmet_implicit_tpbetareduce.scala + // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) + def betaReduce = transform(sym.info.resultType) + + // #3731: return sym1 for which holds: pre bound sym.name to sym and + // pre1 now binds sym.name to sym1, conceptually exactly the same + // symbol as sym. The selection of sym on pre must be updated to the + // selection of sym1 on pre1, since sym's info was probably updated + // by the TypeMap to yield a new symbol, sym1 with transformed info. + // @returns sym1 + override def coevolveSym(pre1: Type): Symbol = + if (pre eq pre1) sym else (pre, pre1) match { + // don't look at parents -- it would be an error to override alias types anyway + case (RefinedType(_, _), RefinedType(_, decls1)) => decls1 lookup sym.name + // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? + case _ => sym + } + + } - //@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs) - def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies) + trait AbstractTypeRef extends NonClassTypeRef { + require(sym.isAbstractType, sym) + + private var symInfoCache: Type = _ + private var thisInfoCache: Type = _ - def thisInfo: Type = - if (sym.isAliasType) normalize - else if (!sym.isNonClassType) sym.info - else { - val symInfo = sym.info - if (thisInfoCache == null || (symInfo ne symInfoCache)) { - symInfoCache = symInfo - thisInfoCache = transformInfo(symInfo) match { - // If a subtyping cycle is not detected here, we'll likely enter an infinite - // loop before a sensible error can be issued. SI-5093 is one example. - case x: SubType if x.supertype eq this => - throw new TypeError("illegal cyclic reference involving " + sym) - case tp => tp + override def isVolatile = { + // need to be careful not to fall into an infinite recursion here + // because volatile checking is done before all cycles are detected. + // the case to avoid is an abstract type directly or + // indirectly upper-bounded by itself. See #2918 + try { + volatileRecursions += 1 + if (volatileRecursions < LogVolatileThreshold) + bounds.hi.isVolatile + else if (pendingVolatiles(sym)) + true // we can return true here, because a cycle will be detected + // here afterwards and an error will result anyway. + else + try { + pendingVolatiles += sym + bounds.hi.isVolatile + } finally { + pendingVolatiles -= sym } + } finally { + volatileRecursions -= 1 + } + } + override def thisInfo = { + val symInfo = sym.info + if (thisInfoCache == null || (symInfo ne symInfoCache)) { + symInfoCache = symInfo + thisInfoCache = transformInfo(symInfo) match { + // If a subtyping cycle is not detected here, we'll likely enter an infinite + // loop before a sensible error can be issued. SI-5093 is one example. + case x: SubType if x.supertype eq this => + throw new TypeError("illegal cyclic reference involving " + sym) + case tp => tp } - thisInfoCache } + thisInfoCache + } + override def isStable = bounds.hi.typeSymbol isSubClass SingletonClass + override def bounds = thisInfo.bounds + // def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies) + override protected def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this + } - def relativeInfo: Type = - if (!sym.isNonClassType) pre.memberInfo(sym) + /** A class for named types of the form + * `<prefix>.<sym.name>[args]` + * Cannot be created directly; one should always use `typeRef` + * for creation. (@M: Otherwise hashing breaks) + * + * @M: a higher-kinded type is represented as a TypeRef with sym.typeParams.nonEmpty, but args.isEmpty + */ + abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type { + private var parentsCache: List[Type] = _ + private var parentsPeriod = NoPeriod + private var baseTypeSeqCache: BaseTypeSeq = _ + private var baseTypeSeqPeriod = NoPeriod + private var normalized: Type = _ + + // @M: propagate actual type params (args) to `tp`, by replacing + // formal type parameters with actual ones. If tp is higher kinded, + // the "actual" type arguments are types that simply reference the + // corresponding type parameters (unbound type variables) + def transform(tp: Type): Type + + // eta-expand, subtyping relies on eta-expansion of higher-kinded types + protected def normalizeImpl: Type = if (isHigherKinded) etaExpand else super.normalize + + // TODO: test case that is compiled in a specific order and in different runs + final override def normalize: Type = { + // arises when argument-dependent types are approximated (see def depoly in implicits) + if (pre eq WildcardType) WildcardType + else if (phase.erasedTypes) normalizeImpl else { - val memberInfo = pre.memberInfo(sym) - if (relativeInfoCache == null || (memberInfo ne memberInfoCache)) { - memberInfoCache = memberInfo - relativeInfoCache = transformInfo(memberInfo) - } - relativeInfoCache + if (normalized eq null) + normalized = normalizeImpl + normalized } + } + + def etaExpand: Type = { + // must initialise symbol, see test/files/pos/ticket0137.scala + val tpars = initializedTypeParams + if (tpars.isEmpty) this + else typeFunAnon(tpars, copyTypeRef(this, pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce? + } - override def typeSymbol = if (sym.isAliasType && (this ne normalize)) normalize.typeSymbol else sym - override def termSymbol = if (sym.isAliasType && (this ne normalize)) normalize.termSymbol else super.termSymbol - override def typeSymbolDirect = sym - override def termSymbolDirect = super.termSymbol + // only need to rebind type aliases, as typeRef already handles abstract types + // (they are allowed to be rebound more liberally) + def coevolveSym(pre1: Type): Symbol = sym -/* @MAT -whenever you see `tp.typeSymbol.isXXXX` and then act on tp based on that predicate, you're on thin ice, -as `typeSymbol` (and `prefix`) automatically normalize, but the other inspectors don't. -In other words, even if `tp.normalize.sym.isXXX` is true, `tp.sym.isXXX` may be false (if sym were a public method to access the non-normalized typeSymbol)... + //@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs) + def transformInfo(tp: Type): Type = appliedType(asSeenFromOwner(tp), args) + + def thisInfo = sym.info + def initializedTypeParams = sym.info.typeParams + def typeParamsMatchArgs = sameLength(initializedTypeParams, args) + def asSeenFromOwner(tp: Type) = tp.asSeenFrom(pre, sym.owner) + + override def baseClasses = thisInfo.baseClasses + override def baseTypeSeqDepth = baseTypeSeq.maxDepth + override def isStable = (sym eq NothingClass) || (sym eq SingletonClass) + override def prefix = pre + override def termSymbol = super.termSymbol + override def termSymbolDirect = super.termSymbol + override def typeArgs = args + override def typeOfThis = transform(sym.typeOfThis) + override def typeSymbol = sym + override def typeSymbolDirect = sym -In retrospect, I think `tp.typeSymbol.isXXX` or (worse) `tp.typeSymbol==XXX` should be replaced by `val tp = tp0.asXXX`. -A type's typeSymbol should never be inspected directly. -*/ + override lazy val isTrivial: Boolean = + !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial) - override def bounds: TypeBounds = - if (sym.isAbstractType) thisInfo.bounds // transform(thisInfo.bounds).asInstanceOf[TypeBounds] // ??? seems to be doing asSeenFrom twice - else super.bounds + override def isNotNull = + sym.isModuleClass || sym == NothingClass || isValueClass(sym) || super.isNotNull override def parents: List[Type] = { val period = parentsPeriod @@ -1894,118 +2035,12 @@ A type's typeSymbol should never be inspected directly. parentsPeriod = currentPeriod if (!isValidForBaseClasses(period)) { parentsCache = thisInfo.parents map transform - } else if (parentsCache == null) { // seems this can happen if things are currupted enough, see #2641 + } else if (parentsCache == null) { // seems this can happen if things are corrupted enough, see #2641 parentsCache = List(AnyClass.tpe) } } parentsCache } - override def typeOfThis = transform(sym.typeOfThis) - -/* - override def narrow = - if (sym.isModuleClass) transform(sym.thisType) - else if (sym.isAliasType) normalize.narrow - else super.narrow -*/ - override def narrow = - if (sym.isModuleClass) singleType(pre, sym.sourceModule) - else if (sym.isAliasType) normalize.narrow - else super.narrow - - override def prefix: Type = - if (sym.isAliasType) normalize.prefix - else pre - - override def typeArgs: List[Type] = args - private def typeArgsOrDummies = if (!isHigherKinded) args else dummyArgs - // def hasFishyArgs = args == dummyArgs - private def argsMatchTypeParams = sameLength(sym.info.typeParams, args) - - // @MAT was typeSymbol.unsafeTypeParams, but typeSymbol normalizes now - private def typeParamsDirect = - if (isDefinitionsInitialized) sym.typeParams - else sym.unsafeTypeParams - - // placeholders derived from type params - private def dummyArgs = { - // @PP to @AM: this appears to me a place where - // higher-order tparams are going off the beam. - // if (sym.isAbstractType) { something goes wrong } - - //@M must be .typeConstructor - typeParamsDirect map (_.typeConstructor) - } - - // (!result.isEmpty) IFF isHigherKinded - override def typeParams: List[Symbol] = if (isHigherKinded) typeParamsDirect else List() - - // note: does not go through typeRef. There's no need to because - // neither `pre` nor `sym` changes. And there's a performance - // advantage to call TypeRef directly. - override def typeConstructor = 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 - // arguments. Note that it doesn't matter whether the symbol refers - // to a java or scala symbol, but it does matter whether it occurs in - // java or scala code. TypeRefs w/o type params that occur in java - // signatures/code are considered raw types, and are represented as - // existential types. - override def isHigherKinded = args.isEmpty && typeParamsDirect.nonEmpty - - override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = - if (isHigherKinded) { - if (sameLength(formals intersect typeParams, typeParams)) - copyTypeRef(this, pre, sym, actuals) - // partial application (needed in infer when bunching type arguments from classes and methods together) - else - copyTypeRef(this, pre, sym, dummyArgs).instantiateTypeParams(formals, actuals) - } - else - super.instantiateTypeParams(formals, actuals) - - /** @pre: argsMatchTypeParams */ - @inline private def betaReduce: Type = { - // isHKSubType0 introduces synthetic type params so that - // betaReduce can first apply sym.info to typeArgs before calling - // asSeenFrom. asSeenFrom then skips synthetic type params, which - // are used to reduce HO subtyping to first-order subtyping, but - // which can't be instantiated from the given prefix and class. - transform(sym.info.resultType) - // this crashes pos/depmet_implicit_tpbetareduce.scala - // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) - } - private def isBetaReducible = sym.isAliasType && argsMatchTypeParams - - // @M: initialize (by sym.info call) needed (see test/files/pos/ticket0137.scala) - @inline private def etaExpand: Type = { - val tpars = sym.info.typeParams // must go through sym.info for typeParams to initialise symbol - if (tpars.isEmpty) this - else typeFunAnon(tpars, copyTypeRef(this, pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce? - } - - override def dealias = if (isBetaReducible) betaReduce.dealias else this - - private def normalize0: Type = ( - if (pre eq WildcardType) WildcardType // arises when argument-dependent types are approximated (see def depoly in implicits) - else if (isHigherKinded) etaExpand // eta-expand, subtyping relies on eta-expansion of higher-kinded types - else if (isBetaReducible) betaReduce.normalize // beta-reduce, but don't do partial application -- cycles have been checked in typeRef - else if (sym.isRefinementClass) sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers - else if (sym.isAliasType) ErrorType //println("!!error: "+(pre, sym, sym.info, sym.info.typeParams, args)) - else super.normalize - ) - - // TODO: test case that is compiled in a specific order and in different runs - override def normalize: Type = { - if (phase.erasedTypes) normalize0 - else { - if (normalized == null) - normalized = normalize0 - - normalized - } - } override def decls: Scope = { sym.info match { @@ -2015,27 +2050,8 @@ A type's typeSymbol should never be inspected directly. } thisInfo.decls } - - override def baseType(clazz: Symbol): Type = - if (sym == clazz) this - else if (sym.isClass) transform(sym.info.baseType(clazz)) - else - try { - basetypeRecursions += 1 - if (basetypeRecursions < LogPendingBaseTypesThreshold) - relativeInfo.baseType(clazz) - else if (pendingBaseTypes contains this) - if (clazz == AnyClass) clazz.tpe else NoType - else - try { - pendingBaseTypes += this - relativeInfo.baseType(clazz) - } finally { - pendingBaseTypes -= this - } - } finally { - basetypeRecursions -= 1 - } + + protected def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform override def baseTypeSeq: BaseTypeSeq = { val period = baseTypeSeqPeriod @@ -2044,9 +2060,7 @@ A type's typeSymbol should never be inspected directly. if (!isValidForBaseClasses(period)) { incCounter(typerefBaseTypeSeqCount) baseTypeSeqCache = undetBaseTypeSeq - baseTypeSeqCache = - if (sym.isAbstractType) transform(bounds.hi).baseTypeSeq prepend this - else sym.info.baseTypeSeq map transform + baseTypeSeqCache = baseTypeSeqImpl } } if (baseTypeSeqCache == undetBaseTypeSeq) @@ -2054,11 +2068,6 @@ A type's typeSymbol should never be inspected directly. baseTypeSeqCache } - override def baseTypeSeqDepth: Int = baseTypeSeq.maxDepth - - override def baseClasses: List[Symbol] = thisInfo.baseClasses - - // override def isNullable: Boolean = sym.info.isNullable private def preString = ( // ensure that symbol is not a local copy with a name coincidence if (!settings.debug.value && shorthands(sym.fullName) && sym.ownerChain.forall(_.isClass)) "" @@ -2073,7 +2082,6 @@ A type's typeSymbol should never be inspected directly. ) else "" ) - private def finishPrefix(rest: String) = ( if (sym.isPackageClass) packagePrefix + rest else if (sym.isModuleClass) objectPrefix + rest @@ -2093,8 +2101,11 @@ A type's typeSymbol should never be inspected directly. // ...but only if it's not a tuple, so ((T1, T2)) => R is distinguishable // from (T1, T2) => R. targs match { - case in :: out :: Nil if !isTupleTypeOrSubtype(in) => - "" + in + " => " + out + case in :: out :: Nil if !isTupleTypeOrSubtype(in) => + // A => B => C should be (A => B) => C or A => (B => C) + val in_s = if (isFunctionType(in)) "(" + in + ")" else "" + in + val out_s = if (isFunctionType(out)) "(" + out + ")" else "" + out + in_s + " => " + out_s case xs => xs.init.mkString("(", ", ", ")") + " => " + xs.last } @@ -2126,12 +2137,19 @@ A type's typeSymbol should never be inspected directly. override def kind = "TypeRef" } - final class UniqueTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends TypeRef(pre, sym, args) with UniqueType { } - object TypeRef extends TypeRefExtractor { - def apply(pre: Type, sym: Symbol, args: List[Type]): Type = { - unique(new UniqueTypeRef(pre, sym, args)) - } + def apply(pre: Type, sym: Symbol, args: List[Type]): Type = unique({ + if (args.nonEmpty) { + if (sym.isAliasType) new ArgsTypeRef(pre, sym, args) with AliasTypeRef + else if (sym.isAbstractType) new ArgsTypeRef(pre, sym, args) with AbstractTypeRef + else new ArgsTypeRef(pre, sym, args) with ClassTypeRef + } + else { + if (sym.isAliasType) new NoArgsTypeRef(pre, sym) with AliasTypeRef + else if (sym.isAbstractType) new NoArgsTypeRef(pre, sym) with AbstractTypeRef + else new NoArgsTypeRef(pre, sym) with ClassTypeRef + } + }) } /** A class representing a method type with parameters. @@ -2320,7 +2338,7 @@ A type's typeSymbol should never be inspected directly. override def isHigherKinded = false override def skolemizeExistential(owner: Symbol, origin: AnyRef) = - deriveType(quantified, tparam => newExistentialSkolem(tparam, owner orElse tparam.owner, origin))(underlying) + deriveType(quantified, tparam => (owner orElse tparam.owner).newExistentialSkolem(tparam, origin))(underlying) private def wildcardArgsString(available: Set[Symbol], args: List[Type]): List[String] = args match { case TypeRef(_, sym, _) :: args1 if (available contains sym) => @@ -2410,7 +2428,7 @@ A type's typeSymbol should never be inspected directly. object HasTypeMember { def apply(name: TypeName, tp: Type): Type = { val bound = refinedType(List(WildcardType), NoSymbol) - val bsym = bound.typeSymbol.newAliasType(NoPosition, name) + val bsym = bound.typeSymbol.newAliasType(name) bsym setInfo tp bound.decls enter bsym bound @@ -3248,6 +3266,20 @@ A type's typeSymbol should never be inspected directly. mapOver(tp) } } + + /** Type with all top-level occurrences of abstract types replaced by their bounds */ + def abstractTypesToBounds(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala ) + case TypeRef(_, sym, _) if sym.isAbstractType => + abstractTypesToBounds(tp.bounds.hi) + case TypeRef(_, sym, _) if sym.isAliasType => + abstractTypesToBounds(tp.normalize) + case rtp @ RefinedType(parents, decls) => + copyRefinedType(rtp, parents mapConserve abstractTypesToBounds, decls) + case AnnotatedType(_, underlying, _) => + abstractTypesToBounds(underlying) + case _ => + tp + } // Set to true for A* => Seq[A] // (And it will only rewrite A* in method result types.) @@ -3298,8 +3330,8 @@ A type's typeSymbol should never be inspected directly. case DeBruijnBinder(pnames, ptypes, restpe) => val isType = pnames.head.isTypeName val newParams = for (name <- pnames) yield - if (isType) owner.newTypeParameter(NoPosition, name.toTypeName) - else owner.newValueParameter(NoPosition, name.toTermName) + if (isType) owner.newTypeParameter(name.toTypeName) + else owner.newValueParameter(name.toTermName) paramStack = newParams :: paramStack try { (newParams, ptypes).zipped foreach ((p, t) => p setInfo this(t)) @@ -3347,7 +3379,9 @@ A type's typeSymbol should never be inspected directly. /** 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. + * constraint and one with Nothing as a lower bound. [Actually + * guarding addLoBound/addHiBound somehow broke raw types so it + * only guards against being created with them.] */ private var lobounds = lo0 filterNot (_.typeSymbolDirect eq NothingClass) private var hibounds = hi0 filterNot (_.typeSymbolDirect eq AnyClass) @@ -3366,8 +3400,7 @@ A type's typeSymbol should never be inspected directly. else if (!isNumericSubType(tp, numlo)) numlo = numericLoBound } - else if (tp.typeSymbolDirect ne NothingClass) - lobounds ::= tp + else lobounds ::= tp } def checkWidening(tp: Type) { @@ -3386,8 +3419,7 @@ A type's typeSymbol should never be inspected directly. else if (!isNumericSubType(numhi, tp)) numhi = numericHiBound } - else if (tp.typeSymbolDirect ne AnyClass) - hibounds ::= tp + else hibounds ::= tp } def isWithinBounds(tp: Type): Boolean = @@ -3482,7 +3514,7 @@ A type's typeSymbol should never be inspected directly. val hi1 = this(hi) if ((lo1 eq lo) && (hi1 eq hi)) tp else TypeBounds(lo1, hi1) - case TypeRef(pre, sym, args) => + case tr @ TypeRef(pre, sym, args) => val pre1 = this(pre) val args1 = if (args.isEmpty) @@ -3495,7 +3527,7 @@ A type's typeSymbol should never be inspected directly. else mapOverArgs(args, tparams) } if ((pre1 eq pre) && (args1 eq args)) tp - else copyTypeRef(tp, pre1, coevolveSym(pre, pre1, sym), args1) + else copyTypeRef(tp, pre1, tr.coevolveSym(pre1), args1) case _ => super.mapOver(tp) } @@ -3510,37 +3542,13 @@ A type's typeSymbol should never be inspected directly. */ 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 - // symbol as sym. The selection of sym on pre must be updated to the - // selection of sym1 on pre1, since sym's info was probably updated - // by the TypeMap to yield a new symbol, sym1 with transformed info. - // @returns sym1 - protected def coevolveSym(pre: Type, pre1: Type, sym: Symbol): Symbol = - if((pre ne pre1) && sym.isAliasType) // only need to rebind type aliases here, as typeRef already handles abstract types (they are allowed to be rebound more liberally) - (pre, pre1) match { - case (RefinedType(_, decls), RefinedType(_, decls1)) => // don't look at parents -- it would be an error to override alias types anyway - //val sym1 = - decls1.lookup(sym.name) -// assert(decls.lookupAll(sym.name).toList.length == 1) -// assert(decls1.lookupAll(sym.name).toList.length == 1) -// assert(sym1.isAliasType) -// println("coevolved "+ sym +" : "+ sym.info +" to "+ sym1 +" : "+ sym1.info +" with "+ pre +" -> "+ pre1) -// sym1 - case _ => // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? -// val sym1 = pre1.nonPrivateMember(sym.name).suchThat(sym => sym.isAliasType) -// println("??coevolve "+ sym +" : "+ sym.info +" to "+ sym1 +" : "+ sym1.info +" with "+ pre +" -> "+ pre1) - sym - } - else sym - /** Map this function over given type */ def mapOver(tp: Type): Type = tp match { - case TypeRef(pre, sym, args) => + case tr @ TypeRef(pre, sym, args) => val pre1 = this(pre) val args1 = args mapConserve this if ((pre1 eq pre) && (args1 eq args)) tp - else copyTypeRef(tp, pre1, coevolveSym(pre, pre1, sym), args1) + else copyTypeRef(tp, pre1, tr.coevolveSym(pre1), args1) case ThisType(_) => tp case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path @@ -3732,7 +3740,7 @@ A type's typeSymbol should never be inspected directly. def typeParamsToExistentials(clazz: Symbol, tparams: List[Symbol]): List[Symbol] = { val eparams = mapWithIndex(tparams)((tparam, i) => - clazz.newExistential(clazz.pos, newTypeName("?"+i)) setInfo tparam.info.bounds) + clazz.newExistential(newTypeName("?"+i), clazz.pos) setInfo tparam.info.bounds) eparams map (_ substInfo (tparams, eparams)) } @@ -3854,10 +3862,10 @@ A type's typeSymbol should never be inspected directly. if (tree.symbol isNonBottomSubClass clazz) && (pre.widen.typeSymbol isNonBottomSubClass tree.symbol) => if (pre.isStable) { // XXX why is this in this method? pull it out and guard the call `annotationArgRewriter.transform(tree)`? - val termSym = - pre.typeSymbol.owner.newValue( - pre.typeSymbol.pos, - pre.typeSymbol.name.toTermName).setInfo(pre) // what symbol should really be used? + val termSym = ( + pre.typeSymbol.owner.newValue(pre.typeSymbol.name.toTermName, pre.typeSymbol.pos) // what symbol should really be used? + setInfo pre + ) gen.mkAttributedQualifier(pre, termSym) } else giveup() @@ -4211,7 +4219,7 @@ A type's typeSymbol should never be inspected directly. val symowner = oldSym.owner val bound = singletonBounds(actualsIndexed(actualIdx)) - val sym = symowner.newExistential(oldSym.pos, newTypeName(oldSym.name + ".type")) + val sym = symowner.newExistential(newTypeName(oldSym.name + ".type"), oldSym.pos) sym.setInfo(bound) sym.setFlag(oldSym.flags) @@ -4599,7 +4607,7 @@ A type's typeSymbol should never be inspected directly. */ def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = { def createDummyClone(pre: Type): Type = { - val dummy = currentOwner.enclClass.newValue(NoPosition, nme.ANYNAME).setInfo(pre.widen) + val dummy = currentOwner.enclClass.newValue(nme.ANYNAME).setInfo(pre.widen) singleType(ThisType(currentOwner.enclClass), dummy) } def maybeCreateDummyClone(pre: Type, sym: Symbol): Type = pre match { @@ -5539,10 +5547,6 @@ A type's typeSymbol should never be inspected directly. } /** Do type arguments `targs` conform to formal parameters `tparams`? - * - * @param tparams ... - * @param targs ... - * @return ... */ def isWithinBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): Boolean = { var bounds = instantiatedBounds(pre, owner, tparams, targs) @@ -5902,7 +5906,7 @@ A type's typeSymbol should never be inspected directly. else { def lubBounds(bnds: List[TypeBounds]): TypeBounds = TypeBounds(glb(bnds map (_.lo), decr(depth)), lub(bnds map (_.hi), decr(depth))) - lubRefined.typeSymbol.newAbstractType(proto.pos, proto.name.toTypeName) + lubRefined.typeSymbol.newAbstractType(proto.name.toTypeName, proto.pos) .setInfoOwnerAdjusted(lubBounds(symtypes map (_.bounds))) } } @@ -6102,6 +6106,26 @@ A type's typeSymbol should never be inspected directly. if (ts exists (_.isNotNull)) res.notNull else res } + + /** A list of the typevars in a type. */ + def typeVarsInType(tp: Type): List[TypeVar] = { + var tvs: List[TypeVar] = Nil + tp foreach { + case t: TypeVar => tvs ::= t + case _ => + } + tvs.reverse + } + /** Make each type var in this type use its original type for comparisons instead + * of collecting constraints. + */ + def suspendTypeVarsInType(tp: Type): List[TypeVar] = { + val tvs = typeVarsInType(tp) + // !!! Is it somehow guaranteed that this will not break under nesting? + // In general one has to save and restore the contents of the field... + tvs foreach (_.suspended = true) + tvs + } /** Compute lub (if `variance == 1`) or glb (if `variance == -1`) of given list * of types `tps`. All types in `tps` are typerefs or singletypes diff --git a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala index 0789f9c774..b21b33e138 100644 --- a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala @@ -297,11 +297,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { case MODULEsym => val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... () if (isModuleRoot) moduleRoot - else { - val m = owner.newModule(name.toTermName, clazz) - clazz.sourceModule = m - m - } + else owner.newLinkedModule(clazz) case VALsym => if (isModuleRoot) { assert(false); NoSymbol } else if (isMethodFlag) owner.newMethod(name.toTermName) diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala index c8cb6febfa..d59fc6d564 100644 --- a/src/compiler/scala/reflect/internal/transform/Erasure.scala +++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala @@ -59,7 +59,7 @@ trait Erasure { // included (use pre.baseType(cls.owner)). // // This requires that cls.isClass. - @inline protected def rebindInnerClass(pre: Type, cls: Symbol): Type = { + protected def rebindInnerClass(pre: Type, cls: Symbol): Type = { if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass? } @@ -75,7 +75,7 @@ trait Erasure { case TypeRef(pre, sym, args) => if (sym == ArrayClass) if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe - else if (args.head.typeSymbol.isBottomClass) arrayType(ObjectClass.tpe) + else if (args.head.typeSymbol.isBottomClass) ObjectArray else typeRef(apply(pre), sym, args map this) else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass) else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass) diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala index 9da75bf2b0..bc5d616ae3 100644 --- a/src/compiler/scala/reflect/runtime/JavaToScala.scala +++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala @@ -45,7 +45,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => def javaClass(path: String): jClass[_] = javaClass(path, defaultReflectiveClassLoader()) def javaClass(path: String, classLoader: JClassLoader): jClass[_] = - classLoader.loadClass(path) + Class.forName(path, true, classLoader) /** Does `path` correspond to a Java class with that fully qualified name? */ def isJavaClass(path: String): Boolean = @@ -115,7 +115,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => * @param jtvar The Java type variable */ private def createTypeParameter(jtvar: jTypeVariable[_ <: GenericDeclaration]): Symbol = { - val tparam = sOwner(jtvar).newTypeParameter(NoPosition, newTypeName(jtvar.getName)) + val tparam = sOwner(jtvar).newTypeParameter(newTypeName(jtvar.getName)) .setInfo(new TypeParamCompleter(jtvar)) tparamCache enter (jtvar, tparam) tparam @@ -154,7 +154,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => override def load(sym: Symbol) = { debugInfo("completing from Java " + sym + "/" + clazz.fullName)//debug assert(sym == clazz || (module != NoSymbol && (sym == module || sym == module.moduleClass)), sym) - val flags = toScalaFlags(jclazz.getModifiers, isClass = true) + val flags = toScalaClassFlags(jclazz.getModifiers) clazz setFlag (flags | JAVA) if (module != NoSymbol) { module setFlag (flags & PRIVATE | JAVA) @@ -335,10 +335,9 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => val name = newTermName(fullname drop (split + 1)) var pkg = owner.info decl name if (pkg == NoSymbol) { - pkg = owner.newPackage(NoPosition, name) + pkg = owner.newPackage(name) pkg.moduleClass setInfo new LazyPackageType - pkg setInfo pkg.moduleClass.tpe - owner.info.decls enter pkg + pkg setInfoAndEnter pkg.moduleClass.tpe info("made Scala "+pkg) } else if (!pkg.isPackage) throw new ReflectError(pkg+" is not a package") @@ -407,7 +406,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => val tparams = new ListBuffer[Symbol] def targToScala(arg: jType): Type = arg match { case jwild: WildcardType => - val tparam = owner.newExistential(NoPosition, newTypeName("T$" + tparams.length)) + val tparam = owner.newExistential(newTypeName("T$" + tparams.length)) .setInfo(TypeBounds( lub(jwild.getLowerBounds.toList map typeToScala), glb(jwild.getUpperBounds.toList map typeToScala map objToAny))) @@ -468,9 +467,11 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => * @return A Scala value symbol that wraps all reflection info of `jfield` */ private def jfieldAsScala(jfield: jField): Symbol = fieldCache.toScala(jfield) { - val field = sOwner(jfield).newValue(NoPosition, newTermName(jfield.getName)) - .setFlag(toScalaFlags(jfield.getModifiers, isField = true) | JAVA) - .setInfo(typeToScala(jfield.getGenericType)) + val field = ( + sOwner(jfield) + newValue(newTermName(jfield.getName), NoPosition, toScalaFieldFlags(jfield.getModifiers)) + setInfo typeToScala(jfield.getGenericType) + ) fieldCache enter (jfield, field) copyAnnotations(field, jfield) field @@ -488,8 +489,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => */ private def jmethodAsScala(jmeth: jMethod): Symbol = methodCache.toScala(jmeth) { val clazz = sOwner(jmeth) - val meth = clazz.newMethod(NoPosition, newTermName(jmeth.getName)) - .setFlag(toScalaFlags(jmeth.getModifiers) | JAVA) + val meth = clazz.newMethod(newTermName(jmeth.getName), NoPosition, toScalaMethodFlags(jmeth.getModifiers)) methodCache enter (jmeth, meth) val tparams = jmeth.getTypeParameters.toList map createTypeParameter val paramtpes = jmeth.getGenericParameterTypes.toList map typeToScala @@ -511,8 +511,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => private def jconstrAsScala(jconstr: jConstructor[_]): Symbol = { // [Martin] Note: I know there's a lot of duplication wrt jmethodAsScala, but don't think it's worth it to factor this out. val clazz = sOwner(jconstr) - val constr = clazz.newMethod(NoPosition, nme.CONSTRUCTOR) - .setFlag(toScalaFlags(jconstr.getModifiers) | JAVA) + val constr = clazz.newConstructor(NoPosition, toScalaMethodFlags(jconstr.getModifiers)) constructorCache enter (jconstr, constr) val tparams = jconstr.getTypeParameters.toList map createTypeParameter val paramtpes = jconstr.getGenericParameterTypes.toList map typeToScala diff --git a/src/compiler/scala/reflect/runtime/Loaders.scala b/src/compiler/scala/reflect/runtime/Loaders.scala index 35b3a16dc2..7aca052fa9 100644 --- a/src/compiler/scala/reflect/runtime/Loaders.scala +++ b/src/compiler/scala/reflect/runtime/Loaders.scala @@ -63,8 +63,8 @@ trait Loaders { self: SymbolTable => */ protected def createClassModule(owner: Symbol, name: TypeName, completer: (Symbol, Symbol) => LazyType) = { assert(!(name.toString endsWith "[]"), name) - val clazz = owner.newClass(NoPosition, name) - val module = owner.newModule(NoPosition, name.toTermName) + val clazz = owner.newClass(name) + val module = owner.newModule(name.toTermName) owner.info.decls enter clazz owner.info.decls enter module initClassModule(clazz, module, completer(clazz, module)) diff --git a/src/compiler/scala/reflect/runtime/Mirror.scala b/src/compiler/scala/reflect/runtime/Mirror.scala index 9490dc4ad7..09a4bbe198 100644 --- a/src/compiler/scala/reflect/runtime/Mirror.scala +++ b/src/compiler/scala/reflect/runtime/Mirror.scala @@ -12,7 +12,16 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe import definitions._ - def classWithName(name: String): Symbol = classToScala(javaClass(name)) + def classWithName(name: String): Symbol = { + val clazz = javaClass(name, defaultReflectiveClassLoader()) + classToScala(clazz) + } + + def getCompanionObject(clazz: Symbol): AnyRef = { + val singleton = ReflectionUtils.singletonInstance(clazz.fullName, defaultReflectiveClassLoader()) + singleton + } + def getClass(obj: AnyRef): Symbol = classToScala(obj.getClass) def getType(obj: AnyRef): Type = typeToScala(obj.getClass) // to do add getClass/getType for instances of primitive types, probably like this: @@ -32,7 +41,9 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe case nme.update => return Array.set(receiver, args(0).asInstanceOf[Int], args(1)) } } - methodToJava(meth).invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*) + + val jmeth = methodToJava(meth) + jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*) } override def classToType(jclazz: java.lang.Class[_]): Type = typeToScala(jclazz) diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala index 231bcdbc0e..8afd6d2231 100644 --- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala +++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala @@ -41,9 +41,12 @@ trait ToolBoxes extends { self: Universe => private def isFree(t: Tree) = t.isInstanceOf[Ident] && t.symbol.isInstanceOf[FreeVar] def typedTopLevelExpr(tree: Tree, pt: Type): Tree = { - val ownerClass = EmptyPackageClass.newClass(newTypeName("<expression-owner>")) - ownerClass.setInfo(new ClassInfoType(List(ObjectClass.tpe), newScope, ownerClass)) - val owner = ownerClass.newLocalDummy(tree.pos) + // !!! Why is this is in the empty package? If it's only to make + // it inaccessible then please put it somewhere designed for that + // rather than polluting the empty package with synthetics. + val ownerClass = EmptyPackageClass.newClassWithInfo(newTypeName("<expression-owner>"), List(ObjectClass.tpe), newScope) + val owner = ownerClass.newLocalDummy(tree.pos) + typer.atOwner(tree, owner).typed(tree, analyzer.EXPRmode, pt) } @@ -53,12 +56,12 @@ trait ToolBoxes extends { self: Universe => } def wrapInObject(expr: Tree, fvs: List[Symbol]): ModuleDef = { - val obj = EmptyPackageClass.newModule(NoPosition, nextWrapperModuleName()) + val obj = EmptyPackageClass.newModule(nextWrapperModuleName()) val minfo = ClassInfoType(List(ObjectClass.tpe, ScalaObjectClass.tpe), new Scope, obj.moduleClass) obj.moduleClass setInfo minfo obj setInfo obj.moduleClass.tpe - val meth = obj.moduleClass.newMethod(NoPosition, newTermName(wrapperMethodName)) - def makeParam(fv: Symbol) = meth.newValueParameter(NoPosition, fv.name.toTermName) setInfo fv.tpe + val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName)) + def makeParam(fv: Symbol) = meth.newValueParameter(fv.name.toTermName) setInfo fv.tpe meth setInfo MethodType(fvs map makeParam, expr.tpe) minfo.decls enter meth trace("wrapping ")(defOwner(expr) -> meth) diff --git a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala b/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala index 9d66ca6c6e..fc4177e956 100644 --- a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala +++ b/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala @@ -39,7 +39,7 @@ trait TreeBuildUtil extends Universe with api.TreeBuildUtil { selectIn(owner.info, idx) } - def freeVar(name: String, info: Type, value: Any) = new FreeVar(newTermName(name), info, value) + def freeVar(name: String, info: Type, value: Any) = newFreeVar(newTermName(name), info, value) def modifiersFromInternalFlags(flags: Long, privateWithin: Name, annotations: List[Tree]): Modifiers = Modifiers(flags, privateWithin, annotations) diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala index 7aff4e3e8e..04ff0c440d 100644 --- a/src/compiler/scala/tools/ant/Scalac.scala +++ b/src/compiler/scala/tools/ant/Scalac.scala @@ -608,7 +608,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared { if (!deprecation.isEmpty) settings.deprecation.value = deprecation.get if (!nobootcp.isEmpty) settings.nobootcp.value = nobootcp.get if (!nowarn.isEmpty) settings.nowarn.value = nowarn.get - if (!optimise.isEmpty) settings.XO.value = optimise.get + if (!optimise.isEmpty) settings.optimise.value = optimise.get if (!unchecked.isEmpty) settings.unchecked.value = unchecked.get if (!usejavacp.isEmpty) settings.usejavacp.value = usejavacp.get diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl index 9f1fbc4524..5949689b24 100644 --- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl @@ -86,4 +86,6 @@ goto :eof :end
@@endlocal
-exit /b %errorlevel%
+
+REM exit code fix, see http://stackoverflow.com/questions/4632891/exiting-batch-with-exit-b-x-where-x-1-acts-as-if-command-completed-successfu
+@@%COMSPEC% /C exit %errorlevel% >nul
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index c388a62644..e805b4e75e 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -193,10 +193,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb def inform[T](msg: String, value: T): T = returning(value)(x => inform(msg + x)) def informTime(msg: String, start: Long) = informProgress(elapsedMessage(msg, start)) - def logResult[T](msg: String)(result: T): T = { - log(msg + ": " + result) - result - } def logError(msg: String, t: Throwable): Unit = () // Over 200 closure objects are eliminated by inlining this. @inline final def log(msg: => AnyRef): Unit = @@ -905,6 +901,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Counts for certain classes of warnings during this run. */ var deprecationWarnings: List[(Position, String)] = Nil var uncheckedWarnings: List[(Position, String)] = Nil + + /** A flag whether macro expansions failed */ + var macroExpansionFailed = false /** Progress tracking. Measured in "progress units" which are 1 per * compilation unit per phase completed. @@ -1087,6 +1086,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb ) warn(deprecationWarnings.size, "deprecation", settings.deprecation) warn(uncheckedWarnings.size, "unchecked", settings.unchecked) + if (macroExpansionFailed) + warning("some macros could not be expanded and code fell back to overridden methods;"+ + "\nrecompiling with generated classfiles on the classpath might help.") // todo: migrationWarnings } } diff --git a/src/compiler/scala/tools/nsc/MacroContext.scala b/src/compiler/scala/tools/nsc/MacroContext.scala index e739eade3a..72662291f8 100644 --- a/src/compiler/scala/tools/nsc/MacroContext.scala +++ b/src/compiler/scala/tools/nsc/MacroContext.scala @@ -2,7 +2,7 @@ package scala.tools.nsc import symtab.Flags._ -trait MacroContext extends reflect.api.MacroContext { self: Global => +trait MacroContext extends reflect.macro.Context { self: Global => def captureVariable(vble: Symbol): Unit = vble setFlag CAPTURED diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index e69c463e71..265d017653 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -30,6 +30,25 @@ abstract class TreeGen extends reflect.internal.TreeGen { else tree } + + /** Builds a fully attributed wildcard import node. + */ + def mkWildcardImport(pkg: Symbol): Import = { + assert(pkg ne null, this) + val qual = gen.mkAttributedStableRef(pkg) + val importSym = ( + NoSymbol + newImport NoPosition + setFlag SYNTHETIC + setInfo analyzer.ImportType(qual) + ) + val importTree = ( + Import(qual, List(ImportSelector(nme.WILDCARD, -1, null, -1))) + setSymbol importSym + setType NoType + ) + importTree + } // wrap the given expression in a SoftReference so it can be gc-ed def mkSoftRef(expr: Tree): Tree = atPos(expr.pos) { @@ -77,17 +96,17 @@ abstract class TreeGen extends reflect.internal.TreeGen { } def mkModuleVarDef(accessor: Symbol) = { + val inClass = accessor.owner.isClass + val extraFlags = if (inClass) PrivateLocal | SYNTHETIC else 0 + val mval = ( - accessor.owner.newVariable(accessor.pos.focus, nme.moduleVarName(accessor.name)) - setInfo accessor.tpe.finalResultType - setFlag (MODULEVAR) + accessor.owner.newVariable(nme.moduleVarName(accessor.name), accessor.pos.focus, MODULEVAR | extraFlags) + setInfo accessor.tpe.finalResultType + addAnnotation VolatileAttr ) + if (inClass) + mval.owner.info.decls enter mval - mval addAnnotation VolatileAttr - if (mval.owner.isClass) { - mval setFlag (PrivateLocal | SYNTHETIC) - mval.owner.info.decls.enter(mval) - } ValDef(mval) } @@ -199,11 +218,7 @@ abstract class TreeGen extends reflect.internal.TreeGen { */ private def mkPackedValDef(expr: Tree, owner: Symbol, name: Name): (ValDef, () => Ident) = { val packedType = typer.packedType(expr, owner) - val sym = ( - owner.newValue(expr.pos.makeTransparent, name) - setFlag SYNTHETIC - setInfo packedType - ) + val sym = owner.newValue(name, expr.pos.makeTransparent, SYNTHETIC) setInfo packedType (ValDef(sym, expr), () => Ident(sym) setPos sym.pos.focus setType expr.tpe) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index 7388ecf163..46ade7d889 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -117,7 +117,7 @@ trait MarkupParsers { * | `{` scalablock `}` */ def xAttributes = { - val aMap = mutable.HashMap[String, Tree]() + val aMap = mutable.LinkedHashMap[String, Tree]() while (isNameStart(ch)) { val start = curOffset diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index d7bfcfc314..fe6dcc9138 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -28,14 +28,17 @@ trait ParsersCommon extends ScannersCommon { val global : Global import global._ - trait ParserCommon { + /** This is now an abstract class, only to work around the optimizer: + * methods in traits are never inlined. + */ + abstract class ParserCommon { val in: ScannerCommon def freshName(prefix: String): Name def freshTermName(prefix: String): TermName def freshTypeName(prefix: String): TypeName def deprecationWarning(off: Int, msg: String): Unit def accept(token: Int): Int - + /** Methods inParensOrError and similar take a second argument which, should * the next token not be the expected opener (e.g. LPAREN) will be returned * instead of the contents of the groupers. However in all cases accept(LPAREN) @@ -123,8 +126,6 @@ self => val global: Global import global._ - private val glob: global.type = global - case class OpInfo(operand: Tree, operator: Name, offset: Offset) class SourceFileParser(val source: SourceFile) extends Parser { @@ -616,7 +617,7 @@ self => def isLiteralToken(token: Int) = token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | - STRINGLIT | STRINGPART | SYMBOLLIT | TRUE | FALSE | NULL => true + STRINGLIT | INTERPOLATIONID | SYMBOLLIT | TRUE | FALSE | NULL => true case _ => false } def isLiteral = isLiteralToken(in.token) @@ -1102,7 +1103,7 @@ self => * }}} * @note The returned tree does not yet have a position */ - def literal(isNegated: Boolean): Tree = { + def literal(isNegated: Boolean = false): Tree = { def finish(value: Any): Tree = { val t = Literal(Constant(value)) in.nextToken() @@ -1110,19 +1111,19 @@ self => } if (in.token == SYMBOLLIT) Apply(scalaDot(nme.Symbol), List(finish(in.strVal))) - else if (in.token == STRINGPART) + else if (in.token == INTERPOLATIONID) interpolatedString() else finish(in.token match { - case CHARLIT => in.charVal - case INTLIT => in.intVal(isNegated).toInt - case LONGLIT => in.intVal(isNegated) - case FLOATLIT => in.floatVal(isNegated).toFloat - case DOUBLELIT => in.floatVal(isNegated) - case STRINGLIT => in.strVal.intern() - case TRUE => true - case FALSE => false - case NULL => null - case _ => + case CHARLIT => in.charVal + case INTLIT => in.intVal(isNegated).toInt + case LONGLIT => in.intVal(isNegated) + case FLOATLIT => in.floatVal(isNegated).toFloat + case DOUBLELIT => in.floatVal(isNegated) + case STRINGLIT | STRINGPART => in.strVal.intern() + case TRUE => true + case FALSE => false + case NULL => null + case _ => syntaxErrorOrIncomplete("illegal literal", true) null }) @@ -1137,16 +1138,27 @@ self => } } - private def interpolatedString(): Tree = { - var t = atPos(o2p(in.offset))(New(TypeTree(definitions.StringBuilderClass.tpe), List(List()))) + private def interpolatedString(): Tree = atPos(in.offset) { + val start = in.offset + val interpolator = in.name + + val partsBuf = new ListBuffer[Tree] + val exprBuf = new ListBuffer[Tree] + in.nextToken() while (in.token == STRINGPART) { - t = stringOp(t, nme.append) - var e = expr() - if (in.token == STRINGFMT) e = stringOp(e, nme.formatted) - t = atPos(t.pos.startOrPoint)(Apply(Select(t, nme.append), List(e))) + partsBuf += literal() + exprBuf += { + if (in.token == IDENTIFIER) atPos(in.offset)(Ident(ident())) + else expr() + } } - if (in.token == STRINGLIT) t = stringOp(t, nme.append) - atPos(t.pos)(Select(t, nme.toString_)) + if (in.token == STRINGLIT) partsBuf += literal() + + val t1 = atPos(o2p(start)) { Ident(nme.StringContext) } + val t2 = atPos(start) { Apply(t1, partsBuf.toList) } + t2 setPos t2.pos.makeTransparent + val t3 = Select(t2, interpolator) setPos t2.pos + atPos(start) { Apply(t3, exprBuf.toList) } } /* ------------- NEW LINES ------------------------------------------------- */ @@ -1468,7 +1480,7 @@ self => atPos(in.offset) { val name = nme.toUnaryName(rawIdent()) // val name = nme.toUnaryName(ident()) // val name: Name = "unary_" + ident() - if (name == nme.UNARY_- && isNumericLit) simpleExprRest(atPos(in.offset)(literal(true)), true) + if (name == nme.UNARY_- && isNumericLit) simpleExprRest(atPos(in.offset)(literal(isNegated = true)), true) else Select(stripParens(simpleExpr()), name) } } @@ -1492,7 +1504,7 @@ self => def simpleExpr(): Tree = { var canApply = true val t = - if (isLiteral) atPos(in.offset)(literal(false)) + if (isLiteral) atPos(in.offset)(literal()) else in.token match { case XMLSTART => xmlLiteral() @@ -1826,7 +1838,7 @@ self => case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => t match { case Ident(nme.MINUS) => - return atPos(start) { literal(true) } + return atPos(start) { literal(isNegated = true) } case _ => } case _ => @@ -1843,8 +1855,8 @@ self => in.nextToken() atPos(start, start) { Ident(nme.WILDCARD) } case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | - STRINGLIT | STRINGPART | SYMBOLLIT | TRUE | FALSE | NULL => - atPos(start) { literal(false) } + STRINGLIT | INTERPOLATIONID | SYMBOLLIT | TRUE | FALSE | NULL => + atPos(start) { literal() } case LPAREN => atPos(start)(makeParens(noSeq.patterns())) case XMLSTART => @@ -2437,7 +2449,7 @@ self => else { val nameOffset = in.offset val name = ident() - if (name == nme.macro_ && isIdent && settings.Xexperimental.value) + if (name == nme.macro_ && isIdent && settings.Xmacros.value) funDefRest(start, in.offset, mods | Flags.MACRO, ident()) else funDefRest(start, nameOffset, mods, name) @@ -2468,6 +2480,9 @@ self => restype = scalaUnitConstr blockExpr() } else { + if (name == nme.macro_ && isIdent && in.token != EQUALS) { + warning("this syntactically invalid code resembles a macro definition. have you forgotten to enable -Xmacros?") + } equalsExpr() } DefDef(newmods, name, tparams, vparamss, restype, rhs) @@ -2527,7 +2542,7 @@ self => newLinesOpt() atPos(start, in.offset) { val name = identForType() - if (name == nme.macro_.toTypeName && isIdent && settings.Xexperimental.value) { + if (name == nme.macro_.toTypeName && isIdent && settings.Xmacros.value) { funDefRest(start, in.offset, mods | Flags.MACRO, identForType()) } else { // @M! a type alias as well as an abstract type may declare type parameters diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index a25b3afbc6..a2a577a7ab 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -161,12 +161,25 @@ trait Scanners extends ScannersCommon { * RBRACKET if region starts with '[' * RBRACE if region starts with '{' * ARROW if region starts with `case' - * STRINGFMT if region is a string interpolation expression starting with '\{' + * STRINGLIT if region is a string interpolation expression starting with '${' + * (the STRINGLIT appears twice in succession on the stack iff the + * expression is a multiline string literal). */ var sepRegions: List[Int] = List() // Get next token ------------------------------------------------------------ + /** Are we directly in a string interpolation expression? + */ + @inline private def inStringInterpolation = + sepRegions.nonEmpty && sepRegions.head == STRINGLIT + + /** Are we directly in a multiline string interpolation expression? + * @pre: inStringInterpolation + */ + @inline private def inMultiLineInterpolation = + sepRegions.tail.nonEmpty && sepRegions.tail.head == STRINGPART + /** read next token and return last offset */ def skipToken(): Offset = { @@ -189,29 +202,31 @@ trait Scanners extends ScannersCommon { sepRegions = RBRACE :: sepRegions case CASE => sepRegions = ARROW :: sepRegions - case STRINGPART => - sepRegions = STRINGFMT :: sepRegions case RBRACE => - sepRegions = sepRegions dropWhile (_ != RBRACE) + while (!sepRegions.isEmpty && sepRegions.head != RBRACE) + sepRegions = sepRegions.tail if (!sepRegions.isEmpty) sepRegions = sepRegions.tail - case RBRACKET | RPAREN | ARROW | STRINGFMT => + docBuffer = null + case RBRACKET | RPAREN => if (!sepRegions.isEmpty && sepRegions.head == lastToken) sepRegions = sepRegions.tail - case _ => - } - (lastToken: @switch) match { - case RBRACE | RBRACKET | RPAREN => docBuffer = null + case ARROW => + if (!sepRegions.isEmpty && sepRegions.head == lastToken) + sepRegions = sepRegions.tail + case STRINGLIT => + if (inStringInterpolation) + sepRegions = sepRegions.tail case _ => } - + // Read a token or copy it from `next` tokenData if (next.token == EMPTY) { lastOffset = charOffset - 1 - if(lastOffset > 0 && buf(lastOffset) == '\n' && buf(lastOffset - 1) == '\r') { + if (lastOffset > 0 && buf(lastOffset) == '\n' && buf(lastOffset - 1) == '\r') { lastOffset -= 1 } - fetchToken() + if (inStringInterpolation) fetchStringPart() else fetchToken() } else { this copyFrom next next.token = EMPTY @@ -308,7 +323,9 @@ trait Scanners extends ScannersCommon { 'z' => putChar(ch) nextChar() - getIdentRest() // scala-mode: wrong indent for multi-line case blocks + getIdentRest() + if (ch == '"' && token == IDENTIFIER && settings.Xexperimental.value) + token = INTERPOLATIONID case '<' => // is XMLSTART? val last = if (charOffset >= 2) buf(charOffset - 2) else ' ' nextChar() @@ -360,18 +377,37 @@ trait Scanners extends ScannersCommon { case '`' => getBackquotedIdent() case '\"' => - nextChar() - if (ch == '\"') { - nextChar() + if (token == INTERPOLATIONID) { + nextRawChar() if (ch == '\"') { nextRawChar() - getMultiLineStringLit() + if (ch == '\"') { + nextRawChar() + getStringPart(multiLine = true) + sepRegions = STRINGLIT :: sepRegions // indicate string part + sepRegions = STRINGLIT :: sepRegions // once more to indicate multi line string part + } else { + token = STRINGLIT + strVal = "" + } } else { - token = STRINGLIT - strVal = "" + getStringPart(multiLine = false) + sepRegions = STRINGLIT :: sepRegions // indicate single line string part } } else { - getStringPart() + nextChar() + if (ch == '\"') { + nextChar() + if (ch == '\"') { + nextRawChar() + getRawStringLit() + } else { + token = STRINGLIT + strVal = "" + } + } else { + getStringLit() + } } case '\'' => nextChar() @@ -397,9 +433,7 @@ trait Scanners extends ScannersCommon { token = DOT } case ';' => - nextChar() - if (inStringInterpolation) getFormatString() - else token = SEMI + nextChar(); token = SEMI case ',' => nextChar(); token = COMMA case '(' => @@ -409,16 +443,7 @@ trait Scanners extends ScannersCommon { case ')' => nextChar(); token = RPAREN case '}' => - if (token == STRINGFMT) { - nextChar() - getStringPart() - } else if (inStringInterpolation) { - strVal = ""; - token = STRINGFMT - } else { - nextChar(); - token = RBRACE - } + nextChar(); token = RBRACE case '[' => nextChar(); token = LBRACKET case ']' => @@ -506,11 +531,6 @@ trait Scanners extends ScannersCommon { } } - /** Are we directly in a string interpolation expression? - */ - private def inStringInterpolation = - sepRegions.nonEmpty && sepRegions.head == STRINGFMT - /** Can token start a statement? */ def inFirstOfStat(token: Int) = token match { case EOF | CATCH | ELSE | EXTENDS | FINALLY | FORSOME | MATCH | WITH | YIELD | @@ -608,71 +628,110 @@ trait Scanners extends ScannersCommon { else finishNamed() } } + + +// Literals ----------------------------------------------------------------- - def getFormatString() = { - getLitChars('}', '"', ' ', '\t') - if (ch == '}') { - setStrVal() - if (strVal.length > 0) strVal = "%" + strVal - token = STRINGFMT - } else { - syntaxError("unclosed format string") - } - } - - def getStringPart() = { - while (ch != '"' && (ch != CR && ch != LF && ch != SU || isUnicodeEscape) && maybeGetLitChar()) {} + private def getStringLit() = { + getLitChars('"') if (ch == '"') { setStrVal() nextChar() token = STRINGLIT - } else if (ch == '{' && settings.Xexperimental.value) { - setStrVal() - nextChar() - token = STRINGPART - } else { - syntaxError("unclosed string literal") - } + } else syntaxError("unclosed string literal") } - private def getMultiLineStringLit() { + private def getRawStringLit(): Unit = { if (ch == '\"') { nextRawChar() - if (ch == '\"') { + if (isTripleQuote()) { + setStrVal() + token = STRINGLIT + } else + getRawStringLit() + } else if (ch == SU) { + incompleteInputError("unclosed multi-line string literal") + } else { + putChar(ch) + nextRawChar() + getRawStringLit() + } + } + + @annotation.tailrec private def getStringPart(multiLine: Boolean): Unit = { + def finishStringPart() = { + setStrVal() + token = STRINGPART + next.lastOffset = charOffset - 1 + next.offset = charOffset - 1 + } + if (ch == '"') { + nextRawChar() + if (!multiLine || isTripleQuote()) { + setStrVal() + token = STRINGLIT + } else + getStringPart(multiLine) + } else if (ch == '$') { + nextRawChar() + if (ch == '$') { + putChar(ch) nextRawChar() - if (ch == '\"') { - nextChar() - while (ch == '\"') { - putChar('\"') - nextChar() - } - token = STRINGLIT - setStrVal() - } else { - putChar('\"') - putChar('\"') - getMultiLineStringLit() - } + getStringPart(multiLine) + } else if (ch == '{') { + finishStringPart() + nextRawChar() + next.token = LBRACE + } else if (Character.isUnicodeIdentifierStart(ch)) { + finishStringPart() + do { + putChar(ch) + nextRawChar() + } while (Character.isUnicodeIdentifierPart(ch)) + next.token = IDENTIFIER + next.name = newTermName(cbuf.toString) + cbuf.clear() } else { - putChar('\"') - getMultiLineStringLit() + syntaxError("invalid string interpolation") } - } else if (ch == SU) { - incompleteInputError("unclosed multi-line string literal") + } else if ((ch == CR || ch == LF || ch == SU) && !isUnicodeEscape) { + syntaxError("unclosed string literal") } else { putChar(ch) nextRawChar() - getMultiLineStringLit() + getStringPart(multiLine) } } + + private def fetchStringPart() = { + offset = charOffset - 1 + getStringPart(multiLine = inMultiLineInterpolation) + } + + private def isTripleQuote(): Boolean = + if (ch == '"') { + nextRawChar() + if (ch == '"') { + nextChar() + while (ch == '"') { + putChar('"') + nextChar() + } + true + } else { + putChar('"') + putChar('"') + false + } + } else { + putChar('"') + false + } -// Literals ----------------------------------------------------------------- - - /** read next character in character or string literal: - * if character sequence is a \{ escape, do not copy it into the string and return false. - * otherwise return true. + /** copy current character into cbuf, interpreting any escape sequences, + * and advance to next character. */ - protected def maybeGetLitChar(): Boolean = { + protected def getLitChar(): Unit = if (ch == '\\') { nextChar() if ('0' <= ch && ch <= '7') { @@ -698,7 +757,6 @@ trait Scanners extends ScannersCommon { case '\"' => putChar('\"') case '\'' => putChar('\'') case '\\' => putChar('\\') - case '{' => return false case _ => invalidEscape() } nextChar() @@ -707,22 +765,16 @@ trait Scanners extends ScannersCommon { putChar(ch) nextChar() } - true - } protected def invalidEscape(): Unit = { syntaxError(charOffset - 1, "invalid escape character") putChar(ch) } - protected def getLitChar(): Unit = - if (!maybeGetLitChar()) invalidEscape() - - private def getLitChars(delimiters: Char*) { - while (!(delimiters contains ch) && (ch != CR && ch != LF && ch != SU || isUnicodeEscape)) { + private def getLitChars(delimiter: Char) = + while (ch != delimiter && (ch != CR && ch != LF && ch != SU || isUnicodeEscape)) { getLitChar() } - } /** read fractional part and exponent of floating point number * if one is present. @@ -971,8 +1023,8 @@ trait Scanners extends ScannersCommon { "string(" + strVal + ")" case STRINGPART => "stringpart(" + strVal + ")" - case STRINGFMT => - "stringfmt(" + strVal + ")" + case INTERPOLATIONID => + "interpolationid(" + name + ")" case SEMI => ";" case NEWLINE => @@ -1088,8 +1140,7 @@ trait Scanners extends ScannersCommon { case LONGLIT => "long literal" case FLOATLIT => "float literal" case DOUBLELIT => "double literal" - case STRINGLIT | STRINGPART => "string literal" - case STRINGFMT => "format string" + case STRINGLIT | STRINGPART | INTERPOLATIONID => "string literal" case SYMBOLLIT => "symbol literal" case LPAREN => "'('" case RPAREN => "')'" diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index 07970bb36e..091f333c27 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -45,18 +45,20 @@ abstract class Tokens { } object Tokens extends Tokens { - final val STRINGPART = 7 + final val STRINGPART = 7 // a part of an interpolated string final val SYMBOLLIT = 8 - final val STRINGFMT = 9 + final val INTERPOLATIONID = 9 // the lead identifier of an interpolated string + def isLiteral(code: Int) = - code >= CHARLIT && code <= SYMBOLLIT + code >= CHARLIT && code <= INTERPOLATIONID + /** identifiers */ final val IDENTIFIER = 10 final val BACKQUOTED_IDENT = 11 def isIdentifier(code: Int) = code >= IDENTIFIER && code <= BACKQUOTED_IDENT - + @switch def canBeginExpression(code: Int) = code match { case IDENTIFIER|BACKQUOTED_IDENT|USCORE => true case LBRACE|LPAREN|LBRACKET|COMMENT => true diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 803bd05031..badf5d70d1 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1528,7 +1528,7 @@ abstract class GenICode extends SubComponent { if (mustUseAnyComparator) { // when -optimise is on we call the @inline-version of equals, found in ScalaRunTime val equalsMethod = - if (!settings.XO.value) { + if (!settings.optimise.value) { def default = platform.externalEquals platform match { case x: JavaPlatform => @@ -1550,7 +1550,7 @@ abstract class GenICode extends SubComponent { val ctx1 = genLoad(l, ctx, ObjectReference) val ctx2 = genLoad(r, ctx1, ObjectReference) - ctx2.bb.emit(CALL_METHOD(equalsMethod, if (settings.XO.value) Dynamic else Static(false))) + ctx2.bb.emit(CALL_METHOD(equalsMethod, if (settings.optimise.value) Dynamic else Static(false))) ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) ctx2.bb.close } @@ -1755,7 +1755,7 @@ abstract class GenICode extends SubComponent { val sym = t.symbol def getLabel(pos: Position, name: Name) = labels.getOrElseUpdate(sym, - method.newLabel(sym.pos, unit.freshTermName(name.toString)) setInfo sym.tpe + method.newLabel(unit.freshTermName(name.toString), sym.pos) setInfo sym.tpe ) t match { @@ -2005,9 +2005,7 @@ abstract class GenICode extends SubComponent { /** Make a fresh local variable. It ensures the 'name' is unique. */ def makeLocal(pos: Position, tpe: Type, name: String): Local = { - val sym = method.symbol.newVariable(pos, unit.freshTermName(name)) - .setInfo(tpe) - .setFlag(Flags.SYNTHETIC) + val sym = method.symbol.newVariable(unit.freshTermName(name), pos, Flags.SYNTHETIC) setInfo tpe this.method.addLocal(new Local(sym, toTypeKind(tpe), false)) } diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index 937b0bdc3d..6421d6c8ef 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -619,6 +619,50 @@ abstract class TypeFlowAnalysis { } } + class MTFAGrowable extends MethodTFA { + + import icodes._ + + /** discards what must be discarded, blanks what needs to be blanked out, and keeps the rest. */ + def reinit(m: icodes.IMethod, staleOut: List[BasicBlock], inlined: collection.Set[BasicBlock], staleIn: collection.Set[BasicBlock]) { + if (this.method == null || this.method.symbol != m.symbol) { + init(m) + return + } else if(staleOut.isEmpty && inlined.isEmpty && staleIn.isEmpty) { + // this promotes invoking reinit if in doubt, no performance degradation will ensue! + return; + } + + reinit { + // asserts conveying an idea what CFG shapes arrive here. + // staleIn foreach (p => assert( !in.isDefinedAt(p), p)) + // staleIn foreach (p => assert(!out.isDefinedAt(p), p)) + // inlined foreach (p => assert( !in.isDefinedAt(p), p)) + // inlined foreach (p => assert(!out.isDefinedAt(p), p)) + // inlined foreach (p => assert(!p.successors.isEmpty || p.lastInstruction.isInstanceOf[icodes.opcodes.THROW], p)) + // staleOut foreach (p => assert( in.isDefinedAt(p), p)) + + // never rewrite in(m.startBlock) + staleOut foreach { b => + if(!inlined.contains(b)) { worklist += b } + out(b) = typeFlowLattice.bottom + } + // nothing else is added to the worklist, bb's reachable via succs will be tfa'ed + blankOut(inlined) + blankOut(staleIn) + // no need to add startBlocks from m.exh + } + } + + private def blankOut(blocks: collection.Set[BasicBlock]) { + blocks foreach { b => + in(b) = typeFlowLattice.bottom + out(b) = typeFlowLattice.bottom + } + } + + } + class Timer { var millis = 0L diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenAndroid.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenAndroid.scala index e7cf716add..1ba5b155fc 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenAndroid.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenAndroid.scala @@ -30,13 +30,14 @@ trait GenAndroid { def isAndroidParcelableClass(sym: Symbol) = (AndroidParcelableInterface != NoSymbol) && - (sym.info.parents contains AndroidParcelableInterface.tpe) + (sym.parentSymbols contains AndroidParcelableInterface) def addCreatorCode(codegen: BytecodeGenerator, block: BasicBlock) { import codegen._ - val fieldSymbol = clasz.symbol.newValue(NoPosition, newTermName(fieldName)) - .setFlag(Flags.STATIC | Flags.FINAL) - .setInfo(AndroidCreatorClass.tpe) + val fieldSymbol = ( + clasz.symbol.newValue(newTermName(fieldName), NoPosition, Flags.STATIC | Flags.FINAL) + setInfo AndroidCreatorClass.tpe + ) val methodSymbol = definitions.getMember(clasz.symbol.companionModule, fieldName) clasz addField new IField(fieldSymbol) block emit CALL_METHOD(methodSymbol, Static(false)) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 03d1bc3ad2..b5232fff09 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -30,13 +30,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with import global._ import icodes._ import icodes.opcodes._ - import definitions.{ - AnyClass, ObjectClass, ThrowsClass, ThrowableClass, ClassfileAnnotationClass, - SerializableClass, StringClass, ClassClass, FunctionClass, - DeprecatedAttr, SerializableAttr, SerialVersionUIDAttr, VolatileAttr, - TransientAttr, CloneableAttr, RemoteAttr, JavaCloneableClass, - RemoteInterfaceClass, RemoteExceptionClass, hasJavaMainMethod - } + import definitions._ val phaseName = "jvm" @@ -68,10 +62,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with def isJavaEntryPoint(clasz: IClass) = { val sym = clasz.symbol - def fail(msg: String) = { + def fail(msg: String, pos: Position = sym.pos) = { clasz.cunit.warning(sym.pos, - sym.name + " has a main method, but " + sym.fullName('.') + " will not be a runnable program.\n" + - " " + msg + ", which means no static forwarder can be generated.\n" + sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" + + " Reason: " + msg // TODO: make this next claim true, if possible // by generating valid main methods as static in module classes // not sure what the jvm allows here @@ -79,19 +73,47 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with ) false } - sym.hasModuleFlag && hasJavaMainMethod(sym) && { - // At this point we've seen a module with a main method, so if this - // doesn't turn out to be a valid entry point, issue a warning. - val companion = sym.linkedClassOfClass - if (companion.isTrait) - fail("Its companion is a trait") - else if (hasJavaMainMethod(companion) && !(sym isSubClass companion)) - fail("Its companion contains its own main method") - // this is only because forwarders aren't smart enough yet - else if (companion.tpe.member(nme.main) != NoSymbol) - fail("Its companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") - else - true + def failNoForwarder(msg: String) = { + fail(msg + ", which means no static forwarder can be generated.\n") + } + val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil + val hasApproximate = possibles exists { m => + m.info match { + case MethodType(p :: Nil, _) => p.tpe.typeSymbol == ArrayClass + case _ => false + } + } + // At this point it's a module with a main-looking method, so either + // succeed or warn that it isn't. + hasApproximate && { + // Before erasure so we can identify generic mains. + atPhase(currentRun.erasurePhase) { + val companion = sym.linkedClassOfClass + val companionMain = companion.tpe.member(nme.main) + + if (hasJavaMainMethod(companion)) + failNoForwarder("companion contains its own main method") + else if (companion.tpe.member(nme.main) != NoSymbol) + // this is only because forwarders aren't smart enough yet + failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") + else if (companion.isTrait) + failNoForwarder("companion is a trait") + // Now either succeeed, or issue some additional warnings for things which look like + // attempts to be java main methods. + else possibles exists { m => + m.info match { + case PolyType(_, _) => + fail("main methods cannot be generic.") + case MethodType(params, res) => + if (res.typeSymbol :: params exists (_.isAbstractType)) + fail("main methods cannot refer to type parameters or abstract types.", m.pos) + else + isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos) + case tp => + fail("don't know what this is: " + tp, m.pos) + } + } + } } } @@ -854,7 +876,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if (outerField != NoSymbol) { log("Adding fake local to represent outer 'this' for closure " + clasz) val _this = new Local( - method.symbol.newVariable(NoPosition, nme.FAKE_LOCAL_THIS), toTypeKind(outerField.tpe), false) + method.symbol.newVariable(nme.FAKE_LOCAL_THIS), toTypeKind(outerField.tpe), false) m.locals = m.locals ::: List(_this) computeLocalVarsIndex(m) // since we added a new local, we need to recompute indexes @@ -944,9 +966,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with serialVUID foreach { value => import Flags._, definitions._ val fieldName = "serialVersionUID" - val fieldSymbol = clasz.symbol.newValue(NoPosition, newTermName(fieldName)) - .setFlag(STATIC | FINAL) - .setInfo(longType) + val fieldSymbol = clasz.symbol.newValue(newTermName(fieldName), NoPosition, STATIC | FINAL) setInfo longType clasz addField new IField(fieldSymbol) lastBlock emit CONSTANT(Constant(value)) lastBlock emit STORE_FIELD(fieldSymbol, true) diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala index a37a3406a8..ec137203bf 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala @@ -203,7 +203,7 @@ abstract class InlineExceptionHandlers extends SubComponent { // Here we could create a single local for all exceptions of a certain type. TODO: try that. val localName = currentClass.cunit.freshTermName("exception$") val localType = exceptionType - val localSymbol = bblock.method.symbol.newValue(NoPosition, localName).setInfo(localType.toType) + val localSymbol = bblock.method.symbol.newValue(localName).setInfo(localType.toType) val local = new Local(localSymbol, localType, false) bblock.method.addLocal(local) diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index e3d21011d1..66f802f74f 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -62,6 +62,15 @@ abstract class Inliners extends SubComponent { override def apply(c: IClass) { inliner analyzeClass c } + + override def run() { + try { + super.run() + } finally { + inliner.NonPublicRefs.usesNonPublics.clear() + inliner.recentTFAs.clear + } + } } def isBottomType(sym: Symbol) = sym == NullClass || sym == NothingClass @@ -79,17 +88,10 @@ abstract class Inliners extends SubComponent { val Private, Protected, Public = Value /** Cache whether a method calls private members. */ - val usesNonPublics: mutable.Map[IMethod, Value] = perRunCaches.newMap() + val usesNonPublics = mutable.Map.empty[IMethod, Value] } import NonPublicRefs._ - /* fresh name counter */ - val fresh = perRunCaches.newMap[String, Int]() withDefaultValue 0 - def freshName(s: String): TermName = { - fresh(s) += 1 - newTermName(s + fresh(s)) - } - private def hasInline(sym: Symbol) = sym hasAnnotation ScalaInlineClass private def hasNoInline(sym: Symbol) = sym hasAnnotation ScalaNoInlineClass @@ -97,27 +99,60 @@ abstract class Inliners extends SubComponent { private var currentIClazz: IClass = _ private def warn(pos: Position, msg: String) = currentIClazz.cunit.warning(pos, msg) + val recentTFAs = mutable.Map.empty[Symbol, Tuple2[Boolean, analysis.MethodTFA]] + private def getRecentTFA(incm: IMethod): (Boolean, analysis.MethodTFA) = { + + def containsRETURN(blocks: List[BasicBlock]) = blocks exists { bb => bb.lastInstruction.isInstanceOf[RETURN] } + + val opt = recentTFAs.get(incm.symbol) + if(opt.isDefined) { + // FYI val cachedBBs = opt.get._2.in.keySet + // FYI assert(incm.blocks.toSet == cachedBBs) + // incm.code.touched plays no role here + return opt.get + } + + val hasRETURN = containsRETURN(incm.code.blocksList) || (incm.exh exists { eh => containsRETURN(eh.blocks) }) + var a: analysis.MethodTFA = null + if(hasRETURN) { a = new analysis.MethodTFA(incm); a.run } + + if(hasInline(incm.symbol)) { recentTFAs.put(incm.symbol, (hasRETURN, a)) } + + (hasRETURN, a) + } + def analyzeClass(cls: IClass): Unit = if (settings.inline.value) { debuglog("Analyzing " + cls) this.currentIClazz = cls - cls.methods filterNot (_.symbol.isConstructor) foreach analyzeMethod + val ms = cls.methods filterNot { _.symbol.isConstructor } + ms foreach { im => + if(hasInline(im.symbol)) { + log("Not inlining into " + im.symbol.originalName.decode + " because it is marked @inline.") + } else if(im.hasCode && !im.symbol.isBridge) { + analyzeMethod(im) + } + } } - val tfa = new analysis.MethodTFA() + val tfa = new analysis.MTFAGrowable() tfa.stat = global.opt.printStats - - // how many times have we already inlined this method here? - private val inlinedMethodCount = perRunCaches.newMap[Symbol, Int]() withDefaultValue 0 + val staleOut = new mutable.ListBuffer[BasicBlock] + val splicedBlocks = mutable.Set.empty[BasicBlock] + val staleIn = mutable.Set.empty[BasicBlock] def analyzeMethod(m: IMethod): Unit = { - var sizeBeforeInlining = if (m.hasCode) m.code.blockCount else 0 - var instrBeforeInlining = if (m.hasCode) m.code.instructionCount else 0 + var sizeBeforeInlining = m.code.blockCount + var instrBeforeInlining = m.code.instructionCount var retry = false var count = 0 - fresh.clear() - inlinedMethodCount.clear() + + // fresh name counter + val fresh = mutable.HashMap.empty[String, Int] withDefaultValue 0 + // how many times have we already inlined this method here? + val inlinedMethodCount = mutable.HashMap.empty[Symbol, Int] withDefaultValue 0 + val caller = new IMethodInfo(m) var info: tfa.lattice.Elem = null @@ -136,17 +171,20 @@ abstract class Inliners extends SubComponent { warn(i.pos, "Could not inline required method %s because %s.".format(msym.originalName.decode, reason)) } - if (shouldLoadImplFor(concreteMethod, receiver)) { + def isAvailable = icodes available concreteMethod.enclClass + + if (!isAvailable && shouldLoadImplFor(concreteMethod, receiver)) { // Until r22824 this line was: // icodes.icode(concreteMethod.enclClass, true) // - // Changing it to the below was the proximate cause for SI-3882: + // Changing it to + // icodes.load(concreteMethod.enclClass) + // was the proximate cause for SI-3882: // error: Illegal index: 0 overlaps List((variable par1,LONG)) // error: Illegal index: 0 overlaps List((variable par1,LONG)) icodes.load(concreteMethod.enclClass) } - def isAvailable = icodes available concreteMethod.enclClass def isCandidate = ( isClosureClass(receiver) || concreteMethod.isEffectivelyFinal @@ -169,7 +207,7 @@ abstract class Inliners extends SubComponent { lookupIMethod(concreteMethod, receiver) match { case Some(callee) => val inc = new IMethodInfo(callee) - val pair = new CallerCalleeInfo(caller, inc) + val pair = new CallerCalleeInfo(caller, inc, fresh, inlinedMethodCount) if (pair isStampedForInlining info.stack) { retry = true @@ -186,6 +224,7 @@ abstract class Inliners extends SubComponent { * might have changed after the inlining. */ usesNonPublics -= m + recentTFAs -= m.symbol } else { if (settings.debug.value) @@ -208,34 +247,35 @@ abstract class Inliners extends SubComponent { import scala.util.control.Breaks._ do { retry = false - if (caller.inline) { - log("Not inlining into " + caller.sym.originalName.decode + " because it is marked @inline.") - } - else if (caller.m.hasCode) { - log("Analyzing " + m + " count " + count + " with " + caller.length + " blocks") - tfa init m - tfa.run - caller.m.linearizedBlocks() foreach { bb => - info = tfa in bb - - breakable { - for (i <- bb) { - i match { - // Dynamic == normal invocations - // Static(true) == calls to private members - case CALL_METHOD(msym, Dynamic | Static(true)) if !msym.isConstructor => - if (analyzeInc(msym, i, bb)) - break - case _ => () - } - info = tfa.interpret(info, i) + log("Analyzing " + m + " count " + count + " with " + caller.length + " blocks") + tfa.reinit(m, staleOut.toList, splicedBlocks, staleIn) + tfa.run + staleOut.clear() + splicedBlocks.clear() + staleIn.clear() + + caller.m.linearizedBlocks() foreach { bb => + info = tfa in bb + + breakable { + for (i <- bb) { + i match { + // Dynamic == normal invocations + // Static(true) == calls to private members + case CALL_METHOD(msym, Dynamic | Static(true)) if !msym.isConstructor => + if (analyzeInc(msym, i, bb)) { + break + } + case _ => () } + info = tfa.interpret(info, i) } } - if (tfa.stat) - log(m.symbol.fullName + " iterations: " + tfa.iterations + " (size: " + caller.length + ")") } + + if (tfa.stat) + log(m.symbol.fullName + " iterations: " + tfa.iterations + " (size: " + caller.length + ")") } while (retry && count < MAX_INLINE_RETRY) @@ -304,11 +344,10 @@ abstract class Inliners extends SubComponent { def inline = hasInline(sym) def noinline = hasNoInline(sym) - def numInlined = inlinedMethodCount(sym) def isBridge = sym.isBridge def isInClosure = isClosureClass(owner) - def isHigherOrder = isHigherOrderMethod(sym) + val isHigherOrder = isHigherOrderMethod(sym) def isMonadic = isMonadicMethod(sym) def handlers = m.exh @@ -317,7 +356,7 @@ abstract class Inliners extends SubComponent { def length = blocks.length def openBlocks = blocks filterNot (_.closed) def instructions = m.code.instructions - def linearized = linearizer linearize m + // def linearized = linearizer linearize m def isSmall = (length <= SMALL_METHOD_SIZE) && blocks(0).length < 10 def isLarge = length > MAX_INLINE_SIZE @@ -336,21 +375,29 @@ abstract class Inliners extends SubComponent { def addHandlers(exhs: List[ExceptionHandler]) = m.exh = exhs ::: m.exh } - class CallerCalleeInfo(val caller: IMethodInfo, val inc: IMethodInfo) { + class CallerCalleeInfo(val caller: IMethodInfo, val inc: IMethodInfo, fresh: mutable.Map[String, Int], inlinedMethodCount: collection.Map[Symbol, Int]) { def isLargeSum = caller.length + inc.length - 1 > SMALL_METHOD_SIZE + private def freshName(s: String): TermName = { + fresh(s) += 1 + newTermName(s + fresh(s)) + } + /** Inline 'inc' into 'caller' at the given block and instruction. * The instruction must be a CALL_METHOD. */ def doInline(block: BasicBlock, instr: Instruction) { + + staleOut += block + val targetPos = instr.pos log("Inlining " + inc.m + " in " + caller.m + " at pos: " + posToStr(targetPos)) def blockEmit(i: Instruction) = block.emit(i, targetPos) def newLocal(baseName: String, kind: TypeKind) = - new Local(caller.sym.newVariable(targetPos, freshName(baseName)), kind, false) + new Local(caller.sym.newVariable(freshName(baseName), targetPos), kind, false) - val a = new analysis.MethodTFA(inc.m) + val (hasRETURN, a) = getRecentTFA(inc.m) /* The exception handlers that are active at the current block. */ val activeHandlers = caller.handlers filter (_ covered block) @@ -379,7 +426,7 @@ abstract class Inliners extends SubComponent { case x => newLocal("$retVal", x) } - val inlinedLocals = perRunCaches.newMap[Local, Local]() + val inlinedLocals = mutable.HashMap.empty[Local, Local] /** Add a new block in the current context. */ def newBlock() = { @@ -400,7 +447,7 @@ abstract class Inliners extends SubComponent { /** alfa-rename `l` in caller's context. */ def dupLocal(l: Local): Local = { - val sym = caller.sym.newVariable(l.sym.pos, freshName(l.sym.name.toString)) + val sym = caller.sym.newVariable(freshName(l.sym.name.toString), l.sym.pos) // sym.setInfo(l.sym.tpe) val dupped = new Local(sym, l.kind, false) inlinedLocals(l) = dupped @@ -461,9 +508,6 @@ abstract class Inliners extends SubComponent { inlinedBlock(b).varsInScope ++= (b.varsInScope map inlinedLocals) } - // analyse callee - a.run - // re-emit the instructions before the call block.open block.clear @@ -478,8 +522,9 @@ abstract class Inliners extends SubComponent { block.close // duplicate the other blocks in the callee - inc.m.linearizedBlocks() foreach { bb => - var info = a in bb + val calleeLin = inc.m.linearizedBlocks() + calleeLin foreach { bb => + var info = if(hasRETURN) (a in bb) else null def emitInlined(i: Instruction) = inlinedBlock(bb).emit(i, targetPos) def emitDrops(toDrop: Int) = info.stack.types drop toDrop foreach (t => emitInlined(DROP(t))) @@ -495,7 +540,7 @@ abstract class Inliners extends SubComponent { case _ => () } emitInlined(map(i)) - info = a.interpret(info, i) + info = if(hasRETURN) a.interpret(info, i) else null } inlinedBlock(bb).close } @@ -503,6 +548,9 @@ abstract class Inliners extends SubComponent { afterBlock emit instrAfter afterBlock.close + staleIn += afterBlock + splicedBlocks ++= (calleeLin map inlinedBlock) + // add exception handlers of the callee caller addHandlers (inc.handlers map translateExh) assert(pending.isEmpty, "Pending NEW elements: " + pending) @@ -520,7 +568,7 @@ abstract class Inliners extends SubComponent { | isSafeToInline: %s | shouldInline: %s """.stripMargin.format( - inc.m, sameSymbols, inc.numInlined < 2, + inc.m, sameSymbols, inlinedMethodCount(inc.sym) < 2, inc.m.hasCode, isSafeToInline(stack), shouldInline ) ) @@ -617,28 +665,22 @@ abstract class Inliners extends SubComponent { var score = 0 - // better not inline inside closures, but hope that the closure itself - // is repeatedly inlined - if (caller.isInClosure) score -= 2 + // better not inline inside closures, but hope that the closure itself is repeatedly inlined + if (caller.isInClosure) score -= 2 else if (caller.inlinedCalls < 1) score -= 1 // only monadic methods can trigger the first inline - if (inc.isSmall) - score += 1 + if (inc.isSmall) score += 1; + if (inc.isLarge) score -= 1; if (caller.isSmall && isLargeSum) { score -= 1 debuglog("shouldInline: score decreased to " + score + " because small " + caller + " would become large") } - if (inc.isLarge) - score -= 1 - if (inc.isMonadic) - score += 3 - else if (inc.isHigherOrder) - score += 1 - if (inc.isInClosure) - score += 2 - if (inc.numInlined > 2) - score -= 2 + if (inc.isMonadic) score += 3 + else if (inc.isHigherOrder) score += 1 + + if (inc.isInClosure) score += 2; + if (inlinedMethodCount(inc.sym) > 2) score -= 2; log("shouldInline(" + inc.m + ") score: " + score) diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala index 14cbdf2f3b..f251fd83fb 100644 --- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala +++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala @@ -166,10 +166,8 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana changesOf(oldSym) = (changes ++ changesErasure).distinct case _ => // a new top level definition - changesOf(sym) = - sym.info.parents.filter(_.typeSymbol.isSealed).map( - p => changeChangeSet(p.typeSymbol, - sym+" extends a sealed "+p.typeSymbol)) + changesOf(sym) = sym.parentSymbols filter (_.isSealed) map (p => + changeChangeSet(p, sym+" extends a sealed "+p)) } } // Create a change for the top level classes that were removed @@ -242,7 +240,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana for ((oldSym, changes) <- changesOf; change <- changes) { def checkParents(cls: Symbol, file: AbstractFile) { - val parentChange = cls.info.parents.exists(_.typeSymbol.fullName == oldSym.fullName) + val parentChange = cls.parentSymbols exists (_.fullName == oldSym.fullName) // if (settings.buildmanagerdebug.value) // compiler.inform("checkParents " + cls + " oldSym: " + oldSym + " parentChange: " + parentChange + " " + cls.info.parents) change match { diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 0dc51d5eb0..7c71438b98 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -110,7 +110,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) class ILoopInterpreter extends IMain(settings, out) { outer => - private class ThreadStoppingLineManager extends Line.Manager(parentClassLoader) { + private class ThreadStoppingLineManager(classLoader: ClassLoader) extends Line.Manager(classLoader) { override def onRunaway(line: Line[_]): Unit = { val template = """ |// She's gone rogue, captain! Have to take her out! @@ -126,8 +126,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) override lazy val formatting = new Formatting { def prompt = ILoop.this.prompt } - override protected def createLineManager(): Line.Manager = - new ThreadStoppingLineManager + override protected def createLineManager(classLoader: ClassLoader): Line.Manager = + new ThreadStoppingLineManager(classLoader) override protected def parentClassLoader = settings.explicitParentLoader.getOrElse( classOf[ILoop].getClassLoader ) diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 0f0ab69e6d..8cdd2334ab 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -269,7 +269,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends /** Create a line manager. Overridable. */ protected def noLineManager = ReplPropsKludge.noThreadCreation(settings) - protected def createLineManager(): Line.Manager = new Line.Manager(_classLoader) + protected def createLineManager(classLoader: ClassLoader): Line.Manager = new Line.Manager(classLoader) /** Instantiate a compiler. Overridable. */ protected def newCompiler(settings: Settings, reporter: Reporter) = { @@ -304,7 +304,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends final def ensureClassLoader() { if (_classLoader == null) { _classLoader = makeClassLoader() - _lineManager = if (noLineManager) null else createLineManager() + _lineManager = if (noLineManager) null else createLineManager(_classLoader) } } def classLoader: AbstractFileClassLoader = { diff --git a/src/compiler/scala/tools/nsc/io/MsilFile.scala b/src/compiler/scala/tools/nsc/io/MsilFile.scala index 69db23923d..d970d0e9c9 100644 --- a/src/compiler/scala/tools/nsc/io/MsilFile.scala +++ b/src/compiler/scala/tools/nsc/io/MsilFile.scala @@ -13,4 +13,6 @@ import ch.epfl.lamp.compiler.msil.{ Type => MsilType, _ } * uniformly, as AbstractFiles. */ class MsilFile(val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) { -}
\ No newline at end of file +} + +object NoMsilFile extends MsilFile(null) { } diff --git a/src/compiler/scala/tools/nsc/io/NoAbstractFile.scala b/src/compiler/scala/tools/nsc/io/NoAbstractFile.scala new file mode 100644 index 0000000000..36cf42d7ec --- /dev/null +++ b/src/compiler/scala/tools/nsc/io/NoAbstractFile.scala @@ -0,0 +1,30 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package io + +import java.io.InputStream + +/** A distinguished object so you can avoid both null + * and Option. + */ +object NoAbstractFile extends AbstractFile { + def absolute: AbstractFile = this + def container: AbstractFile = this + def create(): Unit = ??? + def delete(): Unit = ??? + def file: JFile = null + def input: InputStream = null + def isDirectory: Boolean = false + def iterator: Iterator[AbstractFile] = Iterator.empty + def lastModified: Long = 0L + def lookupName(name: String, directory: Boolean): AbstractFile = null + def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = null + def name: String = "" + def output: java.io.OutputStream = null + def path: String = "" + override def toByteArray = Array[Byte]() +} diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 0d7afdc4ec..0c94e40d68 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -126,11 +126,15 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { if (treeInfo.firstConstructor(stats) == EmptyTree) makeConstructor(List()) :: stats else stats) - def makeParam(name: String, tpt: Tree) = - ValDef(Modifiers(Flags.JAVA | Flags.PARAM), newTermName(name), tpt, EmptyTree) + def makeSyntheticParam(count: Int, tpt: Tree): ValDef = + makeParam(nme.syntheticParamName(count), tpt) + def makeParam(name: String, tpt: Tree): ValDef = + makeParam(newTypeName(name), tpt) + def makeParam(name: TermName, tpt: Tree): ValDef = + ValDef(Modifiers(Flags.JAVA | Flags.PARAM), name, tpt, EmptyTree) def makeConstructor(formals: List[Tree]) = { - val vparams = formals.zipWithIndex map { case (p, i) => makeParam("x$" + (i + 1), p) } + val vparams = mapWithIndex(formals)((p, i) => makeSyntheticParam(i + 1, p)) DefDef(Modifiers(Flags.JAVA), nme.CONSTRUCTOR, List(), List(vparams), TypeTree(), blankExpr) } diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index 61864f0c8a..d81f05cd51 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -252,7 +252,8 @@ trait Matrix extends MatrixAdditions { { val n = if (name == null) cunit.freshTermName("temp") else name // careful: pos has special meaning - recordSyntheticSym(owner.newVariable(pos, n) setInfo tpe setFlag (SYNTHETIC.toLong /: flags)(_|_)) + val flagsLong = (SYNTHETIC.toLong /: flags)(_|_) + recordSyntheticSym(owner.newVariable(n, pos, flagsLong) setInfo tpe) } } }
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 11d829eadb..9d4c9b4411 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -54,7 +54,7 @@ trait ParallelMatching extends ast.TreeDSL } def createLabelDef(namePrefix: String, body: Tree, params: List[Symbol] = Nil, restpe: Type = matchResultType) = { val labelName = cunit.freshTermName(namePrefix) - val labelSym = owner.newLabel(owner.pos, labelName) + val labelSym = owner.newLabel(labelName, owner.pos) val labelInfo = MethodType(params, restpe) LabelDef(labelSym setInfo labelInfo, params, body setType restpe) diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index 967b582f11..c76a04c6ba 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -47,20 +47,7 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr /** Prints the message with the given position indication. */ def printMessage(posIn: Position, msg: String) { - val pos = if (posIn eq null) NoPosition - else if (posIn.isDefined) posIn.inUltimateSource(posIn.source) - else posIn - pos match { - case FakePos(fmsg) => - printMessage(fmsg+" "+msg) - case NoPosition => - printMessage(msg) - case _ => - val buf = new StringBuilder(msg) - val file = pos.source.file - printMessage((if (shortname) file.name else file.path)+":"+pos.line+": "+msg) - printSourceLine(pos) - } + printMessage(Position.formatMessage(posIn, msg, shortname)) } def print(pos: Position, msg: String, severity: Severity) { printMessage(pos, clabel(severity) + msg) diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index efd5323ce2..6806ca03ba 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -96,6 +96,7 @@ trait ScalaSettings extends AbsScalaSettings val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions.") . withPostSetHook(set => List(YmethodInfer, overrideObjects) foreach (_.value = set.value)) // YdepMethTpes, YvirtClasses, + val Xmacros = BooleanSetting ("-Xmacros", "Enable macros.") /** Compatibility stubs for options whose value name did * not previously match the option name. diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 340e1d1d08..4205c2ff36 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -39,7 +39,7 @@ abstract class SymbolLoaders { */ def enterClass(root: Symbol, name: String, completer: SymbolLoader): Symbol = { val owner = realOwner(root) - val clazz = owner.newClass(NoPosition, newTypeName(name)) + val clazz = owner.newClass(newTypeName(name)) clazz setInfo completer enterIfNew(owner, clazz, completer) } @@ -49,7 +49,7 @@ abstract class SymbolLoaders { */ def enterModule(root: Symbol, name: String, completer: SymbolLoader): Symbol = { val owner = realOwner(root) - val module = owner.newModule(NoPosition, newTermName(name)) + val module = owner.newModule(newTermName(name)) module setInfo completer module.moduleClass setInfo moduleClassLoader enterIfNew(owner, module, completer) @@ -199,7 +199,7 @@ abstract class SymbolLoaders { return } } - val pkg = root.newPackage(NoPosition, newTermName(name)) + val pkg = root.newPackage(newTermName(name)) pkg.moduleClass.setInfo(completer) pkg.setInfo(pkg.moduleClass.tpe) root.info.decls.enter(pkg) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index a158012f9f..b818927ceb 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -255,8 +255,11 @@ abstract class ClassfileParser { f = ownerTpe.findMember(origName, 0, 0, false).suchThat(_.tpe =:= tpe) } else { log("Couldn't find " + name + ": " + tpe + " inside: \n" + ownerTpe) - f = if (tpe.isInstanceOf[MethodType]) owner.newMethod(owner.pos, name).setInfo(tpe) - else owner.newValue(owner.pos, name).setInfo(tpe).setFlag(MUTABLE) + f = tpe match { + case MethodType(_, _) => owner.newMethod(name, owner.pos) + case _ => owner.newVariable(name, owner.pos) + } + f setInfo tpe log("created fake member " + f.fullName) } // println("\townerTpe.decls: " + ownerTpe.decls) @@ -283,7 +286,7 @@ abstract class ClassfileParser { if (in.buf(start).toInt != CONSTANT_NAMEANDTYPE) errorBadTag(start) val name = getName(in.getChar(start + 1).toInt) // create a dummy symbol for method types - val dummySym = ownerTpe.typeSymbol.newMethod(ownerTpe.typeSymbol.pos, name) + val dummySym = ownerTpe.typeSymbol.newMethod(name, ownerTpe.typeSymbol.pos) var tpe = getType(dummySym, in.getChar(start + 3).toInt) // fix the return type, which is blindly set to the class currently parsed @@ -455,7 +458,7 @@ abstract class ClassfileParser { ss = name.subName(start, end) sym = owner.info.decls lookup ss if (sym == NoSymbol) { - sym = owner.newPackage(NoPosition, ss) setInfo completer + sym = owner.newPackage(ss) setInfo completer sym.moduleClass setInfo completer owner.info.decls enter sym } @@ -465,11 +468,9 @@ abstract class ClassfileParser { } ss = name.subName(0, start) owner.info.decls lookup ss orElse { - sym = owner.newClass(NoPosition, ss.toTypeName) setInfo completer - if (opt.verboseDebug) - println("loaded "+sym+" from file "+file) - - owner.info.decls enter sym + sym = owner.newClass(ss.toTypeName) setInfoAndEnter completer + debuglog("loaded "+sym+" from file "+file) + sym } } @@ -499,7 +500,7 @@ abstract class ClassfileParser { def parseClass() { val jflags = in.nextChar val isAnnotation = hasAnnotation(jflags) - var sflags = toScalaFlags(jflags, isClass = true) + var sflags = toScalaClassFlags(jflags) var nameIdx = in.nextChar externalName = pool.getClassName(nameIdx) val c = if (externalName.toString.indexOf('$') < 0) pool.getClassSymbol(nameIdx) else clazz @@ -604,13 +605,13 @@ abstract class ClassfileParser { def parseField() { val jflags = in.nextChar - var sflags = toScalaFlags(jflags, isField = true) - if ((sflags & PRIVATE) != 0L && !global.settings.XO.value) { + var sflags = toScalaFieldFlags(jflags) + if ((sflags & PRIVATE) != 0L && !global.settings.optimise.value) { in.skip(4); skipAttributes() } else { val name = pool.getName(in.nextChar) val info = pool.getType(in.nextChar) - val sym = getOwner(jflags).newValue(NoPosition, name).setFlag(sflags) + val sym = getOwner(jflags).newValue(name, NoPosition, sflags) val isEnum = (jflags & JAVA_ACC_ENUM) != 0 sym setInfo { @@ -635,8 +636,8 @@ abstract class ClassfileParser { def parseMethod() { val jflags = in.nextChar.toInt - var sflags = toScalaFlags(jflags) - if (isPrivate(jflags) && !global.settings.XO.value) { + var sflags = toScalaMethodFlags(jflags) + if (isPrivate(jflags) && !global.settings.optimise.value) { val name = pool.getName(in.nextChar) if (name == nme.CONSTRUCTOR) sawPrivateConstructor = true @@ -644,11 +645,11 @@ abstract class ClassfileParser { } else { if ((jflags & JAVA_ACC_BRIDGE) != 0) sflags |= BRIDGE - if ((sflags & PRIVATE) != 0L && global.settings.XO.value) { + if ((sflags & PRIVATE) != 0L && global.settings.optimise.value) { in.skip(4); skipAttributes() } else { val name = pool.getName(in.nextChar) - val sym = getOwner(jflags).newMethod(NoPosition, name).setFlag(sflags) + val sym = getOwner(jflags).newMethod(name, NoPosition, sflags) var info = pool.getType(sym, (in.nextChar)) if (name == nme.CONSTRUCTOR) info match { @@ -726,7 +727,7 @@ abstract class ClassfileParser { else TypeBounds.lower(tp) case '*' => TypeBounds.empty } - val newtparam = sym.newExistential(sym.pos, newTypeName("?"+i)) setInfo bounds + val newtparam = sym.newExistential(newTypeName("?"+i), sym.pos) setInfo bounds existentials += newtparam xs += newtparam.tpe //@M should probably be .tpeHK i += 1 @@ -813,7 +814,7 @@ abstract class ClassfileParser { val start = index while (sig(index) != '>') { val tpname = subName(':'.==).toTypeName - val s = sym.newTypeParameter(NoPosition, tpname) + val s = sym.newTypeParameter(tpname) tparams = tparams + (tpname -> s) sig2typeBounds(tparams, true) newTParams += s @@ -1074,10 +1075,10 @@ abstract class ClassfileParser { def enterClassAndModule(entry: InnerClassEntry, completer: global.loaders.SymbolLoader, jflags: Int) { val name = entry.originalName - var sflags = toScalaFlags(jflags, isClass = true) + var sflags = toScalaClassFlags(jflags) - val innerClass = getOwner(jflags).newClass(NoPosition, name.toTypeName).setInfo(completer).setFlag(sflags) - val innerModule = getOwner(jflags).newModule(NoPosition, name.toTermName).setInfo(completer).setFlag(sflags) + val innerClass = getOwner(jflags).newClass(name.toTypeName).setInfo(completer).setFlag(sflags) + val innerModule = getOwner(jflags).newModule(name.toTermName).setInfo(completer).setFlag(sflags) innerModule.moduleClass setInfo global.loaders.moduleClassLoader getScope(jflags) enter innerClass diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 0b64a49a2c..3c97122c9c 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -60,8 +60,7 @@ abstract class ICodeReader extends ClassfileParser { this.staticCode = new IClass(staticModule) val jflags = in.nextChar val isAttribute = (jflags & JAVA_ACC_ANNOTATION) != 0 - var sflags = toScalaFlags(jflags, true) - if ((sflags & DEFERRED) != 0L) sflags = sflags & ~DEFERRED | ABSTRACT + val sflags = toScalaClassFlags(jflags) // what, this is never used?? val c = pool getClassSymbol in.nextChar parseInnerClasses() @@ -86,29 +85,24 @@ abstract class ICodeReader extends ClassfileParser { val jflags = in.nextChar val name = pool getName in.nextChar val owner = getOwner(jflags) - val dummySym = owner.newMethod(owner.pos, name) setFlag javaToScalaFlags(jflags) + val dummySym = owner.newMethod(name, owner.pos, toScalaMethodFlags(jflags)) try { - val ch = in.nextChar - var tpe = pool.getType(dummySym, ch) + val ch = in.nextChar + val tpe = pool.getType(dummySym, ch) if ("<clinit>" == name.toString) (jflags, NoSymbol) else { val owner = getOwner(jflags) - var sym = owner.info.findMember(name, 0, 0, false).suchThat(old => sameType(old.tpe, tpe)); + var sym = owner.info.findMember(name, 0, 0, false).suchThat(old => sameType(old.tpe, tpe)) if (sym == NoSymbol) - sym = owner.info.findMember(newTermName(name + nme.LOCAL_SUFFIX_STRING), 0, 0, false).suchThat(old => old.tpe =:= tpe); + sym = owner.info.findMember(newTermName(name + nme.LOCAL_SUFFIX_STRING), 0, 0, false).suchThat(_.tpe =:= tpe) if (sym == NoSymbol) { log("Could not find symbol for " + name + ": " + tpe) log(owner.info.member(name).tpe + " : " + tpe) - if (name.toString == "toMap") - tpe = pool.getType(dummySym, ch) - if (field) - sym = owner.newValue(owner.pos, name).setInfo(tpe).setFlag(MUTABLE | javaToScalaFlags(jflags)) - else - sym = dummySym.setInfo(tpe) - owner.info.decls.enter(sym) + sym = if (field) owner.newValue(name, owner.pos, toScalaFieldFlags(jflags)) else dummySym + sym setInfoAndEnter tpe log("added " + sym + ": " + sym.tpe) } (jflags, sym) @@ -119,19 +113,6 @@ abstract class ICodeReader extends ClassfileParser { } } - private def javaToScalaFlags(flags: Int): Long = { - import ch.epfl.lamp.fjbg.JAccessFlags._ - - var res = 0L - if ((flags & ACC_PRIVATE) != 0) res |= Flags.PRIVATE - if ((flags & ACC_PROTECTED) != 0) res |= Flags.PROTECTED - if ((flags & ACC_FINAL) != 0) res |= Flags.FINAL - if ((flags & ACC_ABSTRACT) != 0) res |= Flags.DEFERRED - if ((flags & ACC_SYNTHETIC) != 0) res |= Flags.SYNTHETIC - - res - } - /** Checks if `tp1` is the same type as `tp2`, modulo implicit methods. * We don't care about the distinction between implicit and explicit * methods as this point, and we can't get back the information from @@ -988,7 +969,7 @@ abstract class ICodeReader extends ClassfileParser { /** Return a fresh Local variable for the given index. */ private def freshLocal(idx: Int, kind: TypeKind, isArg: Boolean) = { - val sym = method.symbol.newVariable(NoPosition, newTermName("loc" + idx)).setInfo(kind.toType); + val sym = method.symbol.newVariable(newTermName("loc" + idx)).setInfo(kind.toType); val l = new Local(sym, kind, isArg) method.addLocal(l) l @@ -1005,7 +986,7 @@ abstract class ICodeReader extends ClassfileParser { /** add a method param with the given index. */ def enterParam(idx: Int, kind: TypeKind) = { - val sym = method.symbol.newVariable(NoPosition, newTermName("par" + idx)).setInfo(kind.toType) + val sym = method.symbol.newVariable(newTermName("par" + idx)).setInfo(kind.toType) val l = new Local(sym, kind, true) assert(!locals.isDefinedAt(idx)) locals += (idx -> List((l, kind))) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala index 676c8f09da..ead431c8d7 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala @@ -68,7 +68,7 @@ abstract class MetaParser{ else if (token == "-") { nextToken(); Flags.CONTRAVARIANT } else 0; assert(token startsWith "?", token) - val sym = owner.newTypeParameter(NoPosition, newTypeName(token)).setFlag(vflag) + val sym = owner.newTypeParameter(newTypeName(token)).setFlag(vflag) nextToken() val lo = if (token == ">") { nextToken(); parseType() } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index e7d08ef849..2eddd36db0 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -145,11 +145,8 @@ abstract class Pickler extends SubComponent { val (locals, globals) = sym.children partition (_.isLocalClass) val children = if (locals.isEmpty) globals - else { - val localChildDummy = sym.newClass(sym.pos, tpnme.LOCAL_CHILD) - localChildDummy.setInfo(ClassInfoType(List(sym.tpe), EmptyScope, localChildDummy)) - globals + localChildDummy - } + else globals + sym.newClassWithInfo(tpnme.LOCAL_CHILD, List(sym.tpe), EmptyScope, pos = sym.pos) + putChildren(sym, children.toList sortBy (_.sealedSortName)) } for (annot <- sym.annotations filter (ann => ann.isStatic && !ann.isErroneous) reverse) diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index e0cb0848be..6c238f52cc 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -175,7 +175,7 @@ abstract class TypeParser { // first pass for (tvarCILDef <- typ.getSortedTVars() ) { val tpname = newTypeName(tvarCILDef.Name.replaceAll("!", "")) // TODO are really all type-params named in all assemblies out there? (NO) - val tpsym = clazz.newTypeParameter(NoPosition, tpname) + val tpsym = clazz.newTypeParameter(tpname) classTParams.put(tvarCILDef.Number, tpsym) newTParams += tpsym // TODO wouldn't the following also be needed later, i.e. during getCLRType @@ -259,8 +259,8 @@ abstract class TypeParser { || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ ) { val loader = new loaders.MsilFileLoader(new MsilFile(ntype)) - val nclazz = statics.newClass(NoPosition, ntype.Name.toTypeName) - val nmodule = statics.newModule(NoPosition, ntype.Name) + val nclazz = statics.newClass(ntype.Name.toTypeName) + val nmodule = statics.newModule(ntype.Name) nclazz.setInfo(loader) nmodule.setInfo(loader) staticDefs.enter(nclazz) @@ -449,7 +449,7 @@ abstract class TypeParser { // first pass for (mvarCILDef <- method.getSortedMVars() ) { val mtpname = newTypeName(mvarCILDef.Name.replaceAll("!", "")) // TODO are really all method-level-type-params named in all assemblies out there? (NO) - val mtpsym = methodSym.newTypeParameter(NoPosition, mtpname) + val mtpsym = methodSym.newTypeParameter(mtpname) methodTParams.put(mvarCILDef.Number, mtpsym) newMethodTParams += mtpsym // TODO wouldn't the following also be needed later, i.e. during getCLRType diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index c59a819b02..17d63ea439 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -77,31 +77,51 @@ abstract class AddInterfaces extends InfoTransform { def implClassPhase = currentRun.erasurePhase.next /** Return the implementation class of a trait; create a new one of one does not yet exist */ - def implClass(iface: Symbol): Symbol = implClassMap.getOrElse(iface, { - atPhase(implClassPhase) { - val implName = nme.implClassName(iface.name) - var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol - if (impl != NoSymbol && settings.XO.value) { - log("unlinking impl class " + impl) - iface.owner.info.decls.unlink(impl) - impl = NoSymbol - } - if (impl == NoSymbol) { - impl = iface.cloneSymbolImpl(iface.owner) - impl.name = implName - impl.sourceFile = iface.sourceFile - if (iface.owner.isClass) - iface.owner.info.decls enter impl + def implClass(iface: Symbol): Symbol = { + iface.info + + implClassMap.getOrElse(iface, { + atPhase(implClassPhase) { + log("%s.implClass == %s".format(iface, iface.implClass)) + val implName = nme.implClassName(iface.name) + var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol + impl.info + + val originalImpl = impl + val originalImplString = originalImpl.hasFlagsToString(-1L) + if (impl != NoSymbol) { + // Unlink a pre-existing symbol only if the implementation class is + // visible on the compilation classpath. In general this is true under + // -optimise and not otherwise, but the classpath can use arbitrary + // logic so the classpath must be queried. + if (classPath.context.isValidName(implName + ".class")) { + log("unlinking impl class " + impl) + iface.owner.info.decls.unlink(impl) + impl = NoSymbol + } + else log("not unlinking existing " + impl + " as the impl class is not visible on the classpath.") + } + if (impl == NoSymbol) { + impl = iface.cloneSymbolImpl(iface.owner) + impl.name = implName + impl.sourceFile = iface.sourceFile + if (iface.owner.isClass) + iface.owner.info.decls enter impl + } + if (currentRun.compiles(iface)) currentRun.symSource(impl) = iface.sourceFile + impl setPos iface.pos + impl.flags = iface.flags & ~(INTERFACE | lateINTERFACE) | IMPLCLASS + impl setInfo new LazyImplClassType(iface) + implClassMap(iface) = impl + debuglog( + "generating impl class " + impl + " " + impl.hasFlagsToString(-1L) + " in " + iface.owner + ( + if (originalImpl == NoSymbol) "" else " (cloned from " + originalImpl.fullLocationString + " " + originalImplString + ")" + ) + ) + impl } - if (currentRun.compiles(iface)) currentRun.symSource(impl) = iface.sourceFile - impl setPos iface.pos - impl.flags = iface.flags & ~(INTERFACE | lateINTERFACE) | IMPLCLASS - impl setInfo new LazyImplClassType(iface) - implClassMap(iface) = impl - debuglog("generating impl class " + impl + " in " + iface.owner)//debug - impl - } - }) + }) + } /** A lazy type to set the info of an implementation class * The parents of an implementation class for trait iface are: @@ -121,8 +141,11 @@ abstract class AddInterfaces extends InfoTransform { private def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = { val decls = new Scope if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol) - decls enter (implClass.newMethod(implClass.pos, nme.MIXIN_CONSTRUCTOR) - setInfo MethodType(List(), UnitClass.tpe)) + decls enter ( + implClass.newMethod(nme.MIXIN_CONSTRUCTOR, implClass.pos) + setInfo MethodType(Nil, UnitClass.tpe) + ) + for (sym <- ifaceDecls.iterator) { if (isInterfaceMember(sym)) { if (needsImplMethod(sym)) { @@ -247,8 +270,8 @@ abstract class AddInterfaces extends InfoTransform { addMixinConstructorDef(clazz, templ.body map implMemberDef)) .setSymbol(clazz.newLocalDummy(templ.pos)) } - new ChangeOwnerTraverser(templ.symbol.owner, clazz)( - new ChangeOwnerTraverser(templ.symbol, templ1.symbol)(templ1)) + templ1.changeOwner(templ.symbol.owner -> clazz, templ.symbol -> templ1.symbol) + templ1 } def implClassDefs(trees: List[Tree]): List[Tree] = { diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 034628e95f..50e6139e65 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -143,15 +143,14 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* ### CREATING THE METHOD CACHE ### */ def addStaticVariableToClass(forName: TermName, forType: Type, forInit: Tree, isFinal: Boolean): Symbol = { - val varSym = ( - currentClass.newVariable(ad.pos, mkTerm("" + forName)) - setFlag PRIVATE | STATIC | SYNTHETIC - setInfo forType + val flags = PRIVATE | STATIC | SYNTHETIC | ( + if (isFinal) FINAL else 0 ) - if (isFinal) varSym setFlag FINAL - else varSym.addAnnotation(VolatileAttr) + + val varSym = currentClass.newVariable(mkTerm("" + forName), ad.pos, flags) setInfoAndEnter forType + if (!isFinal) + varSym.addAnnotation(VolatileAttr) - currentClass.info.decls enter varSym val varDef = typedPos( VAL(varSym) === forInit ) newStaticMembers append transform(varDef) @@ -163,13 +162,12 @@ abstract class CleanUp extends Transform with ast.TreeDSL { def addStaticMethodToClass(forName: String, forArgsTypes: List[Type], forResultType: Type) (forBody: Pair[Symbol, List[Symbol]] => Tree): Symbol = { - val methSym = currentClass.newMethod(ad.pos, mkTerm(forName)) - .setFlag(STATIC | SYNTHETIC) - methSym.setInfo(MethodType(methSym.newSyntheticValueParams(forArgsTypes), forResultType)) - currentClass.info.decls enter methSym + val methSym = currentClass.newMethod(mkTerm(forName), ad.pos, STATIC | SYNTHETIC) + val params = methSym.newSyntheticValueParams(forArgsTypes) + methSym setInfoAndEnter MethodType(params, forResultType) - val methDef = typedPos( DefDef(methSym, { forBody(Pair(methSym, methSym.paramss(0))) }) ) + val methDef = typedPos( DefDef(methSym, forBody(methSym -> params)) ) newStaticMembers append transform(methDef) methSym @@ -280,7 +278,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { addStaticMethodToClass(nme.reflMethodName, List(ClassClass.tpe), MethodClass.tpe) { case Pair(reflMethodSym, List(forReceiverSym)) => - val methodSym = reflMethodSym.newVariable(ad.pos, mkTerm("method")) setInfo MethodClass.tpe + val methodSym = reflMethodSym.newVariable(mkTerm("method"), ad.pos) setInfo MethodClass.tpe BLOCK( IF (getPolyCache OBJ_EQ NULL) THEN (safeREF(reflPolyCacheSym) === mkNewPolyCache) ENDIF, @@ -404,7 +402,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { def invocation = (lookup DOT invokeName)(qual1(), invokeArgs) // .invoke(qual1, ...) // exception catching machinery - val invokeExc = currentOwner.newValue(ad.pos, mkTerm("")) setInfo InvocationTargetExceptionClass.tpe + val invokeExc = currentOwner.newValue(mkTerm(""), ad.pos) setInfo InvocationTargetExceptionClass.tpe def catchVar = Bind(invokeExc, Typed(Ident(nme.WILDCARD), TypeTree(InvocationTargetExceptionClass.tpe))) def catchBody = Throw(Apply(Select(Ident(invokeExc), nme.getCause), Nil)) @@ -492,7 +490,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { assert(params.length == mparams.length, mparams) typedPos { - val sym = currentOwner.newValue(ad.pos, mkTerm("qual")) setInfo qual0.tpe + val sym = currentOwner.newValue(mkTerm("qual"), ad.pos) setInfo qual0.tpe qual = safeREF(sym) BLOCK( @@ -565,7 +563,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { case theTry @ Try(block, catches, finalizer) if theTry.tpe.typeSymbol != definitions.UnitClass && theTry.tpe.typeSymbol != definitions.NothingClass => val tpe = theTry.tpe.widen - val tempVar = currentOwner.newVariable(theTry.pos, mkTerm(nme.EXCEPTION_RESULT_PREFIX)).setInfo(tpe) + val tempVar = currentOwner.newVariable(mkTerm(nme.EXCEPTION_RESULT_PREFIX), theTry.pos).setInfo(tpe) def assignBlock(rhs: Tree) = super.transform(BLOCK(Ident(tempVar) === transform(rhs))) val newBlock = assignBlock(block) @@ -637,8 +635,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { // create a symbol for the static field val stfieldSym = ( - currentClass.newVariable(pos, mkTerm("symbol$")) - setFlag PRIVATE | STATIC | SYNTHETIC | FINAL + currentClass.newVariable(mkTerm("symbol$"), pos, PRIVATE | STATIC | SYNTHETIC | FINAL) setInfo SymbolClass.tpe ) currentClass.info.decls enter stfieldSym diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 4d4f4f4c27..23817545e2 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -105,8 +105,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { // Move tree into constructor, take care of changing owner from `oldowner` to constructor symbol def intoConstructor(oldowner: Symbol, tree: Tree) = - intoConstructorTransformer.transform( - new ChangeOwnerTraverser(oldowner, constr.symbol)(tree)) + intoConstructorTransformer transform tree.changeOwner(oldowner -> constr.symbol) // Should tree be moved in front of super constructor call? def canBeMoved(tree: Tree) = tree match { @@ -393,11 +392,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { /** Create a getter or a setter and enter into `clazz` scope */ def addAccessor(sym: Symbol, name: TermName, flags: Long) = { - val m = ( - clazz.newMethod(sym.pos, name) - setFlag (flags & ~LOCAL & ~PRIVATE) - setPrivateWithin clazz - ) + val m = clazz.newMethod(name, sym.pos, flags & ~(LOCAL | PRIVATE)) setPrivateWithin clazz clazz.info.decls enter m } @@ -405,12 +400,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { val getr = addAccessor( sym, nme.getterName(sym.name), getterFlags(sym.flags)) getr setInfo MethodType(List(), sym.tpe) - defBuf += localTyper.typed { - //util.trace("adding getter def for "+getr) { - atPos(sym.pos) { - DefDef(getr, Select(This(clazz), sym)) - }//} - } + defBuf += localTyper.typedPos(sym.pos)(DefDef(getr, Select(This(clazz), sym))) getr } @@ -454,28 +444,24 @@ abstract class Constructors extends Transform with ast.TreeDSL { def delayedInitClosure(stats: List[Tree]) = localTyper.typed { atPos(impl.pos) { - val closureClass = clazz.newClass(impl.pos, nme.delayedInitArg.toTypeName) - .setFlag(SYNTHETIC | FINAL) + val closureClass = clazz.newClass(nme.delayedInitArg.toTypeName, impl.pos, SYNTHETIC | FINAL) val closureParents = List(AbstractFunctionClass(0).tpe, ScalaObjectClass.tpe) - closureClass.setInfo(new ClassInfoType(closureParents, new Scope, closureClass)) - - val outerField = closureClass.newValue(impl.pos, nme.OUTER) - .setFlag(PrivateLocal | PARAMACCESSOR) - .setInfo(clazz.tpe) - - val applyMethod = closureClass.newMethod(impl.pos, nme.apply) - .setFlag(FINAL) - .setInfo(MethodType(List(), ObjectClass.tpe)) - - closureClass.info.decls enter outerField - closureClass.info.decls enter applyMethod - - val outerFieldDef = ValDef(outerField) - - val changeOwner = new ChangeOwnerTraverser(impl.symbol, applyMethod) + closureClass setInfoAndEnter new ClassInfoType(closureParents, new Scope, closureClass) + + val outerField = ( + closureClass + newValue(nme.OUTER, impl.pos, PrivateLocal | PARAMACCESSOR) + setInfoAndEnter clazz.tpe + ) + val applyMethod = ( + closureClass + newMethod(nme.apply, impl.pos, FINAL) + setInfoAndEnter MethodType(Nil, ObjectClass.tpe) + ) + val outerFieldDef = ValDef(outerField) val closureClassTyper = localTyper.atOwner(closureClass) - val applyMethodTyper = closureClassTyper.atOwner(applyMethod) + val applyMethodTyper = closureClassTyper.atOwner(applyMethod) val constrStatTransformer = new Transformer { override def transform(tree: Tree): Tree = tree match { @@ -507,8 +493,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { } else tree case _ => - changeOwner.changeOwner(tree) - tree + tree.changeOwner(impl.symbol -> applyMethod) } } } diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index f3b1e77c8d..71696c24e6 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -768,10 +768,8 @@ abstract class Erasure extends AddInterfaces } ); if (bridgeNeeded) { - val bridge = other.cloneSymbolImpl(owner) - .setPos(owner.pos) - .setFlag(member.flags | BRIDGE) - .resetFlag(ACCESSOR | DEFERRED | LAZY | lateDEFERRED) + val newFlags = (member.flags | BRIDGE) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED) + val bridge = other.cloneSymbolImpl(owner, newFlags) setPos owner.pos // the parameter symbols need to have the new owner bridge.setInfo(otpe.cloneInfo(bridge)) bridgeTarget(bridge) = member diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index cf7d6c94fe..14f3dc16fa 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -91,6 +91,21 @@ abstract class ExplicitOuter extends InfoTransform if (firstTry != NoSymbol && firstTry.outerSource == clazz) firstTry else clazz.info.decls find (_.outerSource == clazz) getOrElse NoSymbol } + def newOuterAccessor(clazz: Symbol) = { + val accFlags = SYNTHETIC | METHOD | STABLE | ( if (clazz.isTrait) DEFERRED else 0 ) + val sym = clazz.newMethodSymbol(nme.OUTER, clazz.pos, accFlags) + val restpe = if (clazz.isTrait) clazz.outerClass.tpe else clazz.outerClass.thisType + + sym expandName clazz + sym.referenced = clazz + sym setInfo MethodType(Nil, restpe) + } + def newOuterField(clazz: Symbol) = { + val accFlags = SYNTHETIC | PARAMACCESSOR | ( if (clazz.isEffectivelyFinal) PrivateLocal else PROTECTED ) + val sym = clazz.newValue(nme.OUTER_LOCAL, clazz.pos, accFlags) + + sym setInfo clazz.outerClass.thisType + } /** <p> * The type transformation method: @@ -136,7 +151,7 @@ abstract class ExplicitOuter extends InfoTransform } if (sym.owner.isTrait) sym setNotFlag PROTECTED // 6 if (sym.isClassConstructor && isInner(sym.owner)) { // 1 - val p = sym.newValueParameter(sym.pos, innerClassConstructorParamName) + val p = sym.newValueParameter(innerClassConstructorParamName, sym.pos) .setInfo(sym.owner.outerClass.thisType) MethodType(p :: params, restpe) } else if (restpe ne restpe1) @@ -146,27 +161,20 @@ abstract class ExplicitOuter extends InfoTransform var decls1 = decls if (isInner(clazz) && !clazz.isInterface) { decls1 = decls.cloneScope - val outerAcc = clazz.newMethod(clazz.pos, nme.OUTER) // 3 + val outerAcc = clazz.newMethod(nme.OUTER, clazz.pos) // 3 outerAcc expandName clazz - - val restpe = if (clazz.isTrait) clazz.outerClass.tpe else clazz.outerClass.thisType - decls1 enter (clazz.newOuterAccessor(clazz.pos) setInfo MethodType(Nil, restpe)) - if (hasOuterField(clazz)) { //2 - val access = if (clazz.isEffectivelyFinal) PrivateLocal else PROTECTED - decls1 enter ( - clazz.newValue(clazz.pos, nme.OUTER_LOCAL) - setFlag (SYNTHETIC | PARAMACCESSOR | access) - setInfo clazz.outerClass.thisType - ) - } + + decls1 enter newOuterAccessor(clazz) + if (hasOuterField(clazz)) //2 + decls1 enter newOuterField(clazz) } if (!clazz.isTrait && !parents.isEmpty) { for (mc <- clazz.mixinClasses) { val mixinOuterAcc: Symbol = atPhase(phase.next)(outerAccessor(mc)) if (mixinOuterAcc != NoSymbol) { if (decls1 eq decls) decls1 = decls.cloneScope - val newAcc = mixinOuterAcc.cloneSymbol(clazz) - newAcc resetFlag DEFERRED setInfo (clazz.thisType memberType mixinOuterAcc) + val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED) + newAcc setInfo (clazz.thisType memberType mixinOuterAcc) decls1 enter newAcc } } @@ -372,15 +380,13 @@ abstract class ExplicitOuter extends InfoTransform def makeGuardDef(vs: List[Symbol], guard: Tree) = { val gdname = unit.freshTermName("gd") - val method = currentOwner.newMethod(tree.pos, gdname) setFlag SYNTHETIC - val fmls = vs map (_.tpe) - val tpe = new MethodType(method newSyntheticValueParams fmls, BooleanClass.tpe) - method setInfo tpe - - localTyper typed (DEF(method) === { - new ChangeOwnerTraverser(currentOwner, method) traverse guard - new TreeSymSubstituter(vs, method.paramss.head) transform (guard) - }) + val method = currentOwner.newMethod(gdname, tree.pos, SYNTHETIC) + val params = method newSyntheticValueParams vs.map(_.tpe) + method setInfo new MethodType(params, BooleanClass.tpe) + + localTyper typed { + DEF(method) === guard.changeOwner(currentOwner -> method).substTreeSyms(vs zip params: _*) + } } val nguard = new ListBuffer[Tree] @@ -475,7 +481,7 @@ abstract class ExplicitOuter extends InfoTransform val vparamss1 = if (isInner(clazz)) { // (4) val outerParam = - sym.newValueParameter(sym.pos, nme.OUTER) setInfo outerField(clazz).info + sym.newValueParameter(nme.OUTER, sym.pos) setInfo outerField(clazz).info ((ValDef(outerParam) setType NoType) :: vparamss.head) :: vparamss.tail } else vparamss super.transform(treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, rhs)) diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 2180fd4f3a..712298bd89 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -9,7 +9,8 @@ package transform import symtab._ import Flags._ import util.TreeSet -import scala.collection.mutable.{ LinkedHashMap, ListBuffer } +import scala.collection.{ mutable, immutable } +import scala.collection.mutable.LinkedHashMap abstract class LambdaLift extends InfoTransform { import global._ @@ -64,6 +65,8 @@ abstract class LambdaLift extends InfoTransform { /** The set of symbols that need to be renamed. */ private val renamable = newSymSet + private val renamableImplClasses = mutable.HashMap[Name, Symbol]() withDefaultValue NoSymbol + /** A flag to indicate whether new free variables have been found */ private var changedFreeVars: Boolean = _ @@ -152,7 +155,21 @@ abstract class LambdaLift extends InfoTransform { tree match { case ClassDef(_, _, _, _) => liftedDefs(tree.symbol) = Nil - if (sym.isLocal) renamable addEntry sym + if (sym.isLocal) { + // Don't rename implementation classes independently of their interfaces. If + // the interface is to be renamed, then we will rename the implementation + // class at that time. You'd think we could call ".implClass" on the trait + // rather than collecting them in another map, but that seems to fail for + // exactly the traits being renamed here (i.e. defined in methods.) + // + // !!! - it makes no sense to have methods like "implClass" and + // "companionClass" which fail for an arbitrary subset of nesting + // arrangements, and then have separate methods which attempt to compensate + // for that failure. There should be exactly one method for any given + // entity which always gives the right answer. + if (sym.isImplClass) renamableImplClasses(nme.interfaceName(sym.name)) = sym + else renamable addEntry sym + } case DefDef(_, _, _, _, _, _) => if (sym.isLocal) { renamable addEntry sym @@ -196,8 +213,8 @@ abstract class LambdaLift extends InfoTransform { for (caller <- called.keys ; callee <- called(caller) ; fvs <- free get callee ; fv <- fvs) markFree(fv, caller) } while (changedFreeVars) - - for (sym <- renamable) { + + def renameSym(sym: Symbol) { val originalName = sym.name val base = sym.name + nme.NAME_JOIN_STRING + ( if (sym.isAnonymousFunction && sym.owner.isMethod) @@ -211,19 +228,35 @@ abstract class LambdaLift extends InfoTransform { debuglog("renaming in %s: %s => %s".format(sym.owner.fullLocationString, originalName, sym.name)) } + /** Rename a trait's interface and implementation class in coordinated fashion. + */ + def renameTrait(traitSym: Symbol, implSym: Symbol) { + val originalImplName = implSym.name + renameSym(traitSym) + implSym.name = nme.implClassName(traitSym.name) + + debuglog("renaming impl class in step with %s: %s => %s".format(traitSym, originalImplName, implSym.name)) + } + + for (sym <- renamable) { + // If we renamed a trait from Foo to Foo$1, we must rename the implementation + // class from Foo$class to Foo$1$class. (Without special consideration it would + // become Foo$class$1 instead.) + val implClass = if (sym.isTrait) renamableImplClasses(sym.name) else NoSymbol + if ((implClass ne NoSymbol) && (sym.owner == implClass.owner)) renameTrait(sym, implClass) + else renameSym(sym) + } + atPhase(phase.next) { for ((owner, freeValues) <- free.toList) { + val newFlags = SYNTHETIC | ( if (owner.isClass) PARAMACCESSOR | PrivateLocal else PARAM ) debuglog("free var proxy: %s, %s".format(owner.fullLocationString, freeValues.toList.mkString(", "))) - - proxies(owner) = - for (fv <- freeValues.toList) yield { - val proxy = owner.newValue(owner.pos, fv.name) - .setFlag(if (owner.isClass) PARAMACCESSOR | PrivateLocal else PARAM) - .setFlag(SYNTHETIC) - .setInfo(fv.info); - if (owner.isClass) owner.info.decls enter proxy; - proxy - } + proxies(owner) = + for (fv <- freeValues.toList) yield { + val proxy = owner.newValue(fv.name, owner.pos, newFlags) setInfo fv.info + if (owner.isClass) owner.info.decls enter proxy + proxy + } } } } @@ -409,12 +442,12 @@ abstract class LambdaLift extends InfoTransform { } else tree1 case Block(stats, expr0) => - val (lzyVals, rest) = stats.partition { - case stat@ValDef(_, _, _, _) if stat.symbol.isLazy => true - case stat@ValDef(_, _, _, _) if stat.symbol.hasFlag(MODULEVAR) => true - case _ => false - } - treeCopy.Block(tree, lzyVals:::rest, expr0) + val (lzyVals, rest) = stats partition { + case stat: ValDef => stat.symbol.isLazy || stat.symbol.isModuleVar + case _ => false + } + if (lzyVals.isEmpty) tree + else treeCopy.Block(tree, lzyVals ::: rest, expr0) case _ => tree } diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index 5452087aa3..f8c5f5bfc6 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -246,7 +246,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD if (bmps.length > n) bmps(n) else { - val sym = meth.newVariable(meth.pos, nme.newBitmapName(nme.BITMAP_NORMAL, n)).setInfo(IntClass.tpe) + val sym = meth.newVariable(nme.newBitmapName(nme.BITMAP_NORMAL, n), meth.pos).setInfo(IntClass.tpe) atPhase(currentRun.typerPhase) { sym addAnnotation VolatileAttr } diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index bc7d1754d4..c5475fa0f2 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -71,6 +71,8 @@ abstract class LiftCode extends Transform with TypingTransformers { case mod => mod.toString } + // I fervently hope this is a test case or something, not anything being + // depended upon. Of more fragile code I cannot conceive. for (line <- (tree.toString.split(Properties.lineSeparator) drop 2 dropRight 1)) { var s = line.trim s = s.replace("$mr.", "") @@ -81,24 +83,23 @@ abstract class LiftCode extends Transform with TypingTransformers { s = s.replace("immutable.this.Nil", "List()") s = s.replace("modifiersFromInternalFlags", "Modifiers") s = s.replace("Modifiers(0L, newTypeName(\"\"), List())", "Modifiers()") - s = """Modifiers\((\d+)L, newTypeName\("(.*?)"\), List\((.*?)\)\)""".r.replaceAllIn(s, m => { - val buf = new StringBuffer() + s = """Modifiers\((\d+)[lL], newTypeName\("(.*?)"\), List\((.*?)\)\)""".r.replaceAllIn(s, m => { + val buf = new StringBuilder val flags = m.group(1).toLong - var s_flags = Flags.modifiersOfFlags(flags) map copypasteModifier - buf.append("Set(" + s_flags.mkString(", ") + ")") + val s_flags = Flags.modifiersOfFlags(flags) map copypasteModifier mkString ", " + if (s_flags != "") + buf.append("Set(" + s_flags + ")") - var privateWithin = m.group(2) - buf.append(", " + "newTypeName(\"" + privateWithin + "\")") + val privateWithin = "" + m.group(2) + if (privateWithin != "") + buf.append(", newTypeName(\"" + privateWithin + "\")") - var annotations = m.group(3) - buf.append(", " + "List(" + annotations + ")") + val annotations = m.group(3) + if (annotations.nonEmpty) + buf.append(", List(" + annotations + ")") - var s = buf.toString - if (s.endsWith(", List()")) s = s.substring(0, s.length - ", List()".length) - if (s.endsWith(", newTypeName(\"\")")) s = s.substring(0, s.length - ", newTypeName(\"\")".length) - if (s.endsWith("Set()")) s = s.substring(0, s.length - "Set()".length) - "Modifiers(" + s + ")" + "Modifiers(" + buf.toString + ")" }) s = """setInternalFlags\((\d+)L\)""".r.replaceAllIn(s, m => { val flags = m.group(1).toLong @@ -310,13 +311,13 @@ abstract class LiftCode extends Transform with TypingTransformers { */ private def reifySymbolDef(sym: Symbol): Tree = { if (reifyDebug) println("reify sym def " + sym) - var rsym: Tree = + + ValDef(NoMods, localName(sym), TypeTree(), Apply( Select(reify(sym.owner), "newNestedSymbol"), - List(reify(sym.pos), reify(sym.name))) - if (sym.flags != 0L) - rsym = Apply(Select(rsym, "setInternalFlags"), List(Literal(Constant(sym.flags)))) - ValDef(NoMods, localName(sym), TypeTree(), rsym) + List(reify(sym.name), reify(sym.pos), Literal(Constant(sym.flags))) + ) + ) } /** diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index c7d3b331a6..bf19cf10e9 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -186,13 +186,9 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { * always accessors and deferred. */ def newGetter(field: Symbol): Symbol = { // println("creating new getter for "+ field +" : "+ field.info +" at "+ field.locationString+(field hasFlag MUTABLE)) - // atPhase(currentRun.erasurePhase){ - // println("before erasure: "+ (field.info)) - // } - clazz.newMethod(field.pos, nme.getterName(field.name)) - .setFlag(field.flags & ~PrivateLocal | ACCESSOR | lateDEFERRED | - (if (field.isMutable) 0 else STABLE)) - .setInfo(MethodType(List(), field.info)) // TODO preserve pre-erasure info? + val newFlags = field.flags & ~PrivateLocal | ACCESSOR | lateDEFERRED | ( if (field.isMutable) 0 else STABLE ) + // TODO preserve pre-erasure info? + clazz.newMethod(nme.getterName(field.name), field.pos, newFlags) setInfo MethodType(Nil, field.info) } /** Create a new setter. Setters are never private or local. They are @@ -200,13 +196,13 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { def newSetter(field: Symbol): Symbol = { //println("creating new setter for "+field+field.locationString+(field hasFlag MUTABLE)) val setterName = nme.getterToSetter(nme.getterName(field.name)) - val setter = clazz.newMethod(field.pos, setterName) - .setFlag(field.flags & ~PrivateLocal | ACCESSOR | lateDEFERRED) - setter.setInfo(MethodType(setter.newSyntheticValueParams(List(field.info)), UnitClass.tpe)) // TODO preserve pre-erasure info? - if (needsExpandedSetterName(field)) { - //println("creating expanded setter from "+field) + val newFlags = field.flags & ~PrivateLocal | ACCESSOR | lateDEFERRED + val setter = clazz.newMethod(setterName, field.pos, newFlags) + // TODO preserve pre-erasure info? + setter setInfo MethodType(setter.newSyntheticValueParams(List(field.info)), UnitClass.tpe) + if (needsExpandedSetterName(field)) setter.name = nme.expandedSetterName(setter.name, clazz) - } + setter } @@ -343,7 +339,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { // so it can no longer be found in the member's owner (the trait) val accessed = atPhase(currentRun.picklerPhase)(member.accessed) val sym = atPhase(currentRun.erasurePhase){ // #3857, need to retain info before erasure when cloning (since cloning only carries over the current entry in the type history) - clazz.newValue(member.pos, nme.getterToLocal(member.name)).setInfo(member.tpe.resultType) // so we have a type history entry before erasure + clazz.newValue(nme.getterToLocal(member.name), member.pos).setInfo(member.tpe.resultType) // so we have a type history entry before erasure } sym.updateInfo(member.tpe.resultType) // info at current phase addMember(clazz, @@ -361,9 +357,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { } else if (member.isMethod && member.isModule && member.hasNoFlags(LIFTED | BRIDGE)) { // mixin objects: todo what happens with abstract objects? - addMember(clazz, member.cloneSymbol(clazz)) - .setPos(clazz.pos) - .resetFlag(DEFERRED | lateDEFERRED) + addMember(clazz, member.cloneSymbol(clazz, member.flags & ~(DEFERRED | lateDEFERRED)) setPos clazz.pos) } } } @@ -396,9 +390,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { if (sourceModule != NoSymbol) { sourceModule setPos sym.pos sourceModule.flags = MODULE | FINAL - } else { - sourceModule = clazz.owner.newModule( - sym.pos, sym.name.toTermName, sym.asInstanceOf[ClassSymbol]) + } + else { + sourceModule = ( + clazz.owner.newModuleSymbol(sym.name.toTermName, sym.pos, MODULE | FINAL) + setModuleClass sym.asInstanceOf[ClassSymbol] + ) clazz.owner.info.decls enter sourceModule } sourceModule setInfo sym.tpe @@ -530,9 +527,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { if (currentOwner.isImplClass) { if (isImplementedStatically(sym)) { sym setFlag notOVERRIDE - self = sym.newValue(sym.pos, nme.SELF) - .setFlag(PARAM) - .setInfo(toInterface(currentOwner.typeOfThis)); + self = sym.newValueParameter(nme.SELF, sym.pos) setInfo toInterface(currentOwner.typeOfThis) val selfdef = ValDef(self) setType NoType treeCopy.DefDef(tree, mods, name, tparams, List(selfdef :: vparams), tpt, rhs) } else { @@ -742,7 +737,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { assert(!sym.isOverloaded, sym) def createBitmap: Symbol = { - val sym = clazz0.newVariable(clazz0.pos, bitmapName) setInfo IntClass.tpe + val sym = clazz0.newVariable(bitmapName, clazz0.pos) setInfo IntClass.tpe atPhase(currentRun.typerPhase)(sym addAnnotation VolatileAttr) category match { diff --git a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala index 73d17458bf..f7d2c9de28 100644 --- a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala @@ -37,8 +37,8 @@ abstract class SampleTransform extends Transform { Select( // The `Select` factory method is defined in class `Trees` sup, currentOwner.newValue( // creates a new term symbol owned by `currentowner` - tree1.pos, - newTermName("sample")))))) // The standard term name creator + newTermName("sample"), // The standard term name creator + tree1.pos))))) case _ => tree1 } diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 99b0a82690..fd826fb6d8 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -64,6 +64,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { type TypeEnv = immutable.Map[Symbol, Type] def emptyEnv: TypeEnv = Map[Symbol, Type]() + private implicit val typeOrdering: Ordering[Type] = Ordering[String] on ("" + _.typeSymbol.name) import definitions.{ @@ -73,6 +74,34 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { AnyRefClass, ObjectClass, Predef_AnyRef, uncheckedVarianceClass } + + /** TODO - this is a lot of maps. + */ + + /** For a given class and concrete type arguments, give its specialized class */ + val specializedClass: mutable.Map[(Symbol, TypeEnv), Symbol] = new mutable.LinkedHashMap + + /** Map a method symbol to a list of its specialized overloads in the same class. */ + private val overloads: mutable.Map[Symbol, List[Overload]] = mutable.HashMap[Symbol, List[Overload]]() withDefaultValue Nil + + /** Map a symbol to additional information on specialization. */ + private val info: mutable.Map[Symbol, SpecializedInfo] = perRunCaches.newMap[Symbol, SpecializedInfo]() + + /** Map class symbols to the type environments where they were created. */ + private val typeEnv = mutable.HashMap[Symbol, TypeEnv]() withDefaultValue emptyEnv + + // holds mappings from regular type parameter symbols to symbols of + // specialized type parameters which are subtypes of AnyRef + private val anyrefSpecCache = perRunCaches.newMap[Symbol, Symbol]() + + // holds mappings from members to the type variables in the class + // that they were already specialized for, so that they don't get + // specialized twice (this is for AnyRef specializations) + private val wasSpecializedForTypeVars = perRunCaches.newMap[Symbol, Set[Symbol]]() withDefaultValue Set() + + /** Concrete methods that use a specialized type, or override such methods. */ + private val concreteSpecMethods = new mutable.HashSet[Symbol]() + private def isSpecialized(sym: Symbol) = sym hasAnnotation SpecializedClass private def hasSpecializedFlag(sym: Symbol) = sym hasFlag SPECIALIZED private def specializedTypes(tps: List[Symbol]) = tps filter isSpecialized @@ -135,21 +164,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } - /** For a given class and concrete type arguments, give its specialized class */ - val specializedClass: mutable.Map[(Symbol, TypeEnv), Symbol] = new mutable.LinkedHashMap - - /** Returns the generic class that was specialized to 'cls', or - * 'cls' itself if cls is not a specialized subclass. + /** Returns the generic class that was specialized to 'sClass', or + * 'sClass' itself if sClass is not a specialized subclass. */ - def genericClass(cls: Symbol): Symbol = - if (hasSpecializedFlag(cls)) cls.info.parents.head.typeSymbol - else cls - - /** Map a method symbol to a list of its specialized overloads in the same class. */ - private val overloads: mutable.Map[Symbol, List[Overload]] = - new mutable.HashMap[Symbol, List[Overload]] { - override def default(key: Symbol): List[Overload] = Nil - } + def genericClass(sClass: Symbol): Symbol = + if (hasSpecializedFlag(sClass)) sClass.superClass + else sClass case class Overload(sym: Symbol, env: TypeEnv) { override def toString = "specialized overload " + sym + " in " + env @@ -227,9 +247,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } - /** Map a symbol to additional information on specialization. */ - private val info: mutable.Map[Symbol, SpecializedInfo] = perRunCaches.newMap[Symbol, SpecializedInfo]() - /** Has `clazz` any type parameters that need be specialized? */ def hasSpecializedParams(clazz: Symbol) = clazz.info.typeParams exists isSpecialized @@ -398,25 +415,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case _ => Set() } - // holds mappings from regular type parameter symbols to symbols of - // specialized type parameters which are subtypes of AnyRef - private val anyrefSpecCache = perRunCaches.newMap[Symbol, Symbol]() - - /** Returns the type parameter in the specialized class `cls` that corresponds to type parameter + /** Returns the type parameter in the specialized class `clazz` that corresponds to type parameter * `sym` in the original class. It will create it if needed or use the one from the cache. */ - private def typeParamSubAnyRef(sym: Symbol, cls: Symbol) = ( + private def typeParamSubAnyRef(sym: Symbol, clazz: Symbol) = ( anyrefSpecCache.getOrElseUpdate(sym, - cls.newTypeParameter(sym.pos, sym.name append nme.SPECIALIZED_SUFFIX_NAME toTypeName) + clazz.newTypeParameter(sym.name append nme.SPECIALIZED_SUFFIX_NAME toTypeName, sym.pos) setInfo TypeBounds(sym.info.bounds.lo, AnyRefClass.tpe) ).tpe ) /** Cleans the anyrefSpecCache of all type parameter symbols of a class. */ - private def cleanAnyRefSpecCache(cls: Symbol, decls: List[Symbol]) = ( + private def cleanAnyRefSpecCache(clazz: Symbol, decls: List[Symbol]) = ( // remove class type parameters and those of normalized members. - cls :: decls foreach { + clazz :: decls foreach { _.tpe match { case PolyType(tparams, _) => anyrefSpecCache --= tparams case _ => () @@ -424,12 +437,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } ) - // holds mappings from members to the type variables in the class - // that they were already specialized for, so that they don't get - // specialized twice (this is for AnyRef specializations) - private val wasSpecializedForTypeVars = - perRunCaches.newMap[Symbol, immutable.Set[Symbol]]() withDefaultValue immutable.Set[Symbol]() - /** Type parameters that survive when specializing in the specified environment. */ def survivingParams(params: List[Symbol], env: TypeEnv) = params.filter(p => !isSpecialized(p) || !isScalaValueType(env(p))) @@ -479,38 +486,35 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ def specializeClass(clazz: Symbol, outerEnv: TypeEnv): List[Symbol] = { def specializedClass(env0: TypeEnv, normMembers: List[Symbol]): Symbol = { - val cls = clazz.owner.newClass(clazz.pos, specializedName(clazz, env0).toTypeName) - .setFlag(SPECIALIZED | clazz.flags) - .resetFlag(CASE) - cls.sourceFile = clazz.sourceFile - currentRun.symSource(cls) = clazz.sourceFile // needed later on by mixin - - val env = mapAnyRefsInSpecSym(env0, clazz, cls) - - typeEnv(cls) = env - this.specializedClass((clazz, env0)) = cls + /** It gets hard to follow all the clazz and cls, and specializedClass + * was both already used for a map and mucho long. So "sClass" is the + * specialized subclass of "clazz" throughout this file. + */ + val sClass = clazz.owner.newClass(specializedName(clazz, env0).toTypeName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE) - // declarations of the newly specialized class 'cls' - val decls1 = new Scope + def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long) = + member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED)) + + sClass.sourceFile = clazz.sourceFile + currentRun.symSource(sClass) = clazz.sourceFile // needed later on by mixin - // original unspecialized type parameters - var oldClassTParams: List[Symbol] = Nil + val env = mapAnyRefsInSpecSym(env0, clazz, sClass) + typeEnv(sClass) = env + this.specializedClass((clazz, env0)) = sClass - // unspecialized type parameters of 'cls' (cloned) - var newClassTParams: List[Symbol] = Nil + val decls1 = new Scope // declarations of the newly specialized class 'sClass' + var oldClassTParams: List[Symbol] = Nil // original unspecialized type parameters + var newClassTParams: List[Symbol] = Nil // unspecialized type parameters of 'specializedClass' (cloned) // has to be a val in order to be computed early. It is later called // within 'atPhase(next)', which would lead to an infinite cycle otherwise val specializedInfoType: Type = { - // val (_, unspecParams) = splitParams(clazz.info.typeParams) - // oldClassTParams = unspecParams - val survivedParams = survivingParams(clazz.info.typeParams, env) - oldClassTParams = survivedParams - newClassTParams = produceTypeParameters(survivedParams, cls, env) map subst(env) + oldClassTParams = survivingParams(clazz.info.typeParams, env) + newClassTParams = produceTypeParameters(oldClassTParams, sClass, env) map subst(env) // log("new tparams " + newClassTParams.zip(newClassTParams map {s => (s.tpe, s.tpe.bounds.hi)}) + ", in env: " + env) def applyContext(tpe: Type) = - subst(env, tpe).instantiateTypeParams(survivedParams, newClassTParams map (_.tpe)) + subst(env, tpe).instantiateTypeParams(oldClassTParams, newClassTParams map (_.tpe)) /** Return a list of specialized parents to be re-mixed in a specialized subclass. * Assuming env = [T -> Int] and @@ -520,25 +524,24 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * so that class Integral$mci extends Integral[Int] with Numeric$mcI. */ def specializedParents(parents: List[Type]): List[Type] = { - val res = new mutable.ListBuffer[Type] - // log(cls + ": seeking specialized parents of class with parents: " + parents.map(_.typeSymbol)) + var res: List[Type] = Nil + // log(specializedClass + ": seeking specialized parents of class with parents: " + parents.map(_.typeSymbol)) for (p <- parents) { - // log(p.typeSymbol) val stp = atPhase(phase.next)(specializedType(p)) if (stp != p) - if (p.typeSymbol.isTrait) res += stp + if (p.typeSymbol.isTrait) res ::= stp else if (currentRun.compiles(clazz)) reporter.warning(clazz.pos, p.typeSymbol + " must be a trait. Specialized version of " + clazz + " will inherit generic " + p) // TODO change to error } - res.reverse.toList + res } var parents = List(applyContext(atPhase(currentRun.typerPhase)(clazz.tpe))) // log("!!! Parents: " + parents + ", sym: " + parents.map(_.typeSymbol)) if (parents.head.typeSymbol.isTrait) parents = parents.head.parents.head :: parents - val extraSpecializedMixins = specializedParents(clazz.info.parents.map(applyContext)) + val extraSpecializedMixins = specializedParents(clazz.info.parents map applyContext) if (extraSpecializedMixins.nonEmpty) debuglog("specializeClass on " + clazz + " founds extra specialized mixins: " + extraSpecializedMixins.mkString(", ")) // If the class being specialized has a self-type, the self type may @@ -547,17 +550,16 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // already be covered. Then apply the current context to the self-type // as with the parents and assign it to typeOfThis. if (clazz.typeOfThis.typeConstructor ne clazz.typeConstructor) { - cls.typeOfThis = applyContext(clazz.typeOfThis) + sClass.typeOfThis = applyContext(clazz.typeOfThis) log("Rewriting self-type for specialized class:\n" + - " " + clazz.defStringSeenAs(clazz.typeOfThis) + "\n" + - " => " + cls.defStringSeenAs(cls.typeOfThis) + " " + clazz.defStringSeenAs(clazz.typeOfThis) + "\n" + + " => " + sClass.defStringSeenAs(sClass.typeOfThis) ) } - val infoType = ClassInfoType(parents ::: extraSpecializedMixins, decls1, cls) - if (newClassTParams.isEmpty) infoType else PolyType(newClassTParams, infoType) + polyType(newClassTParams, ClassInfoType(parents ::: extraSpecializedMixins, decls1, sClass)) } - atPhase(phase.next)(cls.setInfo(specializedInfoType)) + atPhase(phase.next)(sClass setInfo specializedInfoType) val fullEnv = outerEnv ++ env /** Enter 'sym' in the scope of the current specialized class. It's type is @@ -567,13 +569,13 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ def enterMember(sym: Symbol): Symbol = { typeEnv(sym) = fullEnv ++ typeEnv(sym) // append the full environment - sym modifyInfo (_.substThis(clazz, cls).instantiateTypeParams(oldClassTParams, newClassTParams map (_.tpe))) + sym modifyInfo (_.substThis(clazz, sClass).instantiateTypeParams(oldClassTParams, newClassTParams map (_.tpe))) // we remove any default parameters. At this point, they have been all // resolved by the type checker. Later on, erasure re-typechecks everything and // chokes if it finds default parameters for specialized members, even though // they are never needed. mapParamss(sym)(_ resetFlag DEFAULTPARAM) - decls1.enter(subst(fullEnv)(sym)) + decls1 enter subst(fullEnv)(sym) } /** Create and enter in scope an overridden symbol m1 for `m` that forwards @@ -590,13 +592,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * def m$I(x: Int) = <body>/adapted to env {A -> Int} // om */ def forwardToOverload(m: Symbol): Symbol = { - val specMember = ( - enterMember(m cloneSymbol cls) - setFlag (OVERRIDE | SPECIALIZED) - resetFlag (DEFERRED | CASEACCESSOR) - ) // m1 - - val om = specializedOverload(cls, m, env).setFlag(OVERRIDE) + val specMember = enterMember(cloneInSpecializedClass(m, f => (f | OVERRIDE) & ~(DEFERRED | CASEACCESSOR))) + val om = specializedOverload(sClass, m, env).setFlag(OVERRIDE) val original = info.get(m) match { case Some(NormalizedMember(tg)) => tg case _ => m @@ -617,7 +614,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { m.resetFlag(PRIVATE).setFlag(PROTECTED) if (m.isConstructor) { - val specCtor = enterMember(m.cloneSymbol(cls) setFlag SPECIALIZED) + val specCtor = enterMember(cloneInSpecializedClass(m, x => x)) info(specCtor) = Forward(m) } else if (isNormalizedMember(m)) { // methods added by normalization @@ -625,7 +622,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (nonConflicting(env ++ typeEnv(m))) { if (info(m).degenerate) { debuglog("degenerate normalized member " + m + " info(m): " + info(m)) - val specMember = enterMember(m.cloneSymbol(cls)).setFlag(SPECIALIZED).resetFlag(DEFERRED) + val specMember = enterMember(cloneInSpecializedClass(m, _ & ~DEFERRED)) info(specMember) = Implementation(original) typeEnv(specMember) = env ++ typeEnv(m) @@ -639,7 +636,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { log("conflicting env for " + m + " env: " + env) } else if (m.isDeferred) { // abstract methods - val specMember = enterMember(m.cloneSymbol(cls)).setFlag(SPECIALIZED).setFlag(DEFERRED) + val specMember = enterMember(cloneInSpecializedClass(m, _ | DEFERRED)) debuglog("deferred " + specMember.fullName + " remains abstract") info(specMember) = new Abstract(specMember) @@ -652,24 +649,18 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else if (m.isValue && !m.isMethod) { // concrete value definition def mkAccessor(field: Symbol, name: Name) = { - val sym = ( - cls.newMethod(field.pos, name) - setFlag (SPECIALIZED | m.getter(clazz).flags) - resetFlag (LOCAL | PARAMACCESSOR | CASEACCESSOR | LAZY) - // we rely on the super class to initialize param accessors - ) + val newFlags = (SPECIALIZED | m.getter(clazz).flags) & ~(LOCAL | CASEACCESSOR | PARAMACCESSOR | LAZY) + // we rely on the super class to initialize param accessors + val sym = sClass.newMethod(name, field.pos, newFlags) info(sym) = SpecializedAccessor(field) sym } def overrideIn(clazz: Symbol, sym: Symbol) = { - val sym1 = ( - sym cloneSymbol clazz - setFlag (OVERRIDE | SPECIALIZED) - resetFlag (DEFERRED | CASEACCESSOR | PARAMACCESSOR | LAZY) - ) + val newFlags = (sym.flags | OVERRIDE | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | PARAMACCESSOR | LAZY) + val sym1 = sym.cloneSymbol(clazz, newFlags) sym1 modifyInfo (_ asSeenFrom (clazz.tpe, sym1.owner)) } - val specVal = specializedOverload(cls, m, env) + val specVal = specializedOverload(sClass, m, env) addConcreteSpecMethod(m) specVal.asInstanceOf[TermSymbol].setAlias(m) @@ -678,15 +669,15 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // create accessors debuglog("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name)) if (nme.isLocalName(m.name)) { - val specGetter = mkAccessor(specVal, nme.localToGetter(specVal.name)).setInfo(MethodType(List(), specVal.info)) - val origGetter = overrideIn(cls, m.getter(clazz)) + val specGetter = mkAccessor(specVal, nme.localToGetter(specVal.name)) setInfo MethodType(Nil, specVal.info) + val origGetter = overrideIn(sClass, m.getter(clazz)) info(origGetter) = Forward(specGetter) enterMember(specGetter) enterMember(origGetter) debuglog("created accessors: " + specGetter + " orig: " + origGetter) clazz.caseFieldAccessors.find(_.name.startsWith(m.name)) foreach { cfa => - val cfaGetter = overrideIn(cls, cfa) + val cfaGetter = overrideIn(sClass, cfa) info(cfaGetter) = SpecializedAccessor(specVal) enterMember(cfaGetter) debuglog("found case field accessor for " + m + " added override " + cfaGetter); @@ -697,7 +688,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { .resetFlag(STABLE) specSetter.setInfo(MethodType(specSetter.newSyntheticValueParams(List(specVal.info)), UnitClass.tpe)) - val origSetter = overrideIn(cls, m.setter(clazz)) + val origSetter = overrideIn(sClass, m.setter(clazz)) info(origSetter) = Forward(specSetter) enterMember(specSetter) enterMember(origSetter) @@ -707,7 +698,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { specVal.resetFlag(PRIVATE) } } else if (m.isClass) { - val specClass: Symbol = m.cloneSymbol(cls).setFlag(SPECIALIZED) + val specClass: Symbol = cloneInSpecializedClass(m, x => x) typeEnv(specClass) = fullEnv specClass.name = specializedName(specClass, fullEnv).toTypeName enterMember(specClass) @@ -715,7 +706,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { info(specClass) = SpecializedInnerClass(m, fullEnv) } } - cls + sClass } val decls1 = clazz.info.decls.toList flatMap { m: Symbol => @@ -783,7 +774,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } for (env0 <- specializations(specializingOn) if needsSpecialization(env0, sym)) yield { val tps = survivingParams(sym.info.typeParams, env0) - val specMember = sym.cloneSymbol(owner).setFlag(SPECIALIZED).resetFlag(DEFERRED) + val specMember = sym.cloneSymbol(owner, (sym.flags | SPECIALIZED) & ~DEFERRED) val env = mapAnyRefsInSpecSym(env0, sym, specMember) val (keys, vals) = env.toList.unzip @@ -857,14 +848,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Return the specialized overload of `m`, in the given environment. */ private def specializedOverload(owner: Symbol, sym: Symbol, env: TypeEnv): Symbol = { - val specMember = sym.cloneSymbol(owner) // this method properly duplicates the symbol's info + // this method properly duplicates the symbol's info + val specMember = sym.cloneSymbol(owner, (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR | ACCESSOR | LAZY)) specMember.name = specializedName(sym, env) - - (specMember - modifyInfo (info => subst(env, info.asSeenFrom(owner.thisType, sym.owner))) - setFlag (SPECIALIZED) - resetFlag (DEFERRED | CASEACCESSOR | ACCESSOR | LAZY) - ) + specMember modifyInfo (info => subst(env, info.asSeenFrom(owner.thisType, sym.owner))) } /** For each method m that overrides an inherited method m', add a special @@ -1023,9 +1010,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } - /** Map class symbols to the type environments where they were created. */ - private val typeEnv = mutable.HashMap[Symbol, TypeEnv]() withDefaultValue emptyEnv - /** Apply type bindings in the given environment `env` to all declarations. */ private def subst(env: TypeEnv, decls: List[Symbol]): List[Symbol] = decls map subst(env) @@ -1212,11 +1196,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { clazz.owner.info.decl(originalName).suchThat(_.isClass) } else NoSymbol - def illegalSpecializedInheritance(clazz: Symbol): Boolean = { - hasSpecializedFlag(clazz) && originalClass(clazz).info.parents.exists { p => - hasSpecializedParams(p.typeSymbol) && !p.typeSymbol.isTrait - } - } + def illegalSpecializedInheritance(clazz: Symbol): Boolean = ( + hasSpecializedFlag(clazz) + && originalClass(clazz).parentSymbols.exists(p => hasSpecializedParams(p) && !p.isTrait) + ) def specializeCalls(unit: CompilationUnit) = new TypingTransformer(unit) { /** Map a specializable method to it's rhs, when not deferred. */ @@ -1275,7 +1258,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { .format(tree, symbol.tpe, tree.tpe, env, specializedName(symbol, env))) if (!env.isEmpty) { // a method? val specCandidates = qual.tpe.member(specializedName(symbol, env)) - val specMember = specCandidates suchThat (s => doesConform(symbol, tree.tpe, s.tpe, env)) + val specMember = specCandidates suchThat { s => + doesConform(symbol, tree.tpe, qual.tpe.memberType(s), env) + } + log("[specSym] found: " + specCandidates.tpe + ", instantiated as: " + tree.tpe) log("[specSym] found specMember: " + specMember) if (specMember ne NoSymbol) @@ -1588,20 +1574,20 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, tmp) } - /** Create trees for specialized members of 'cls', based on the + /** Create trees for specialized members of 'sClass', based on the * symbols that are already there. */ - private def makeSpecializedMembers(cls: Symbol): List[Tree] = { + private def makeSpecializedMembers(sClass: Symbol): List[Tree] = { // add special overrides first -// if (!cls.hasFlag(SPECIALIZED)) -// for (m <- specialOverrides(cls)) cls.info.decls.enter(m) +// if (!specializedClass.hasFlag(SPECIALIZED)) +// for (m <- specialOverrides(specializedClass)) specializedClass.info.decls.enter(m) val mbrs = new mutable.ListBuffer[Tree] var hasSpecializedFields = false - for (m <- cls.info.decls + for (m <- sClass.info.decls if m.hasFlag(SPECIALIZED) && (m.sourceFile ne null) - && satisfiable(typeEnv(m), !cls.hasFlag(SPECIALIZED))) { + && satisfiable(typeEnv(m), !sClass.hasFlag(SPECIALIZED))) { log("creating tree for " + m.fullName) if (m.isMethod) { if (info(m).target.hasAccessorFlag) hasSpecializedFields = true @@ -1609,16 +1595,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val origParamss = parameters(info(m).target) val vparams = ( map2(m.info.paramTypes, origParamss(0))((tp, sym) => - m.newValue(sym.pos, specializedName(sym, typeEnv(cls))) - .setInfo(tp) - .setFlag(sym.flags) + m.newValue(specializedName(sym, typeEnv(sClass)), sym.pos, sym.flags) setInfo tp ) ) // param accessors for private members (the others are inherited from the generic class) if (m.isPrimaryConstructor) { - for (param <- vparams ; if cls.info.nonPrivateMember(param.name) == NoSymbol) { - val acc = param.cloneSymbol(cls).setFlag(PARAMACCESSOR | PRIVATE) - cls.info.decls.enter(acc) + for (param <- vparams ; if sClass.info.nonPrivateMember(param.name) == NoSymbol) { + val acc = param.cloneSymbol(sClass, param.flags | PARAMACCESSOR | PRIVATE) + sClass.info.decls.enter(acc) mbrs += ValDef(acc, EmptyTree).setType(NoType).setPos(m.pos) } } @@ -1638,10 +1622,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } if (hasSpecializedFields) { - val isSpecializedInstance = cls.hasFlag(SPECIALIZED) || cls.info.parents.exists(_.typeSymbol.hasFlag(SPECIALIZED)) - val sym = cls.newMethod(nme.SPECIALIZED_INSTANCE, cls.pos) - .setInfo(MethodType(Nil, BooleanClass.tpe)) - cls.info.decls.enter(sym) + val isSpecializedInstance = sClass :: sClass.parentSymbols exists (_ hasFlag SPECIALIZED) + val sym = sClass.newMethod(nme.SPECIALIZED_INSTANCE, sClass.pos) setInfoAndEnter MethodType(Nil, BooleanClass.tpe) + mbrs += atPos(sym.pos) { DefDef(sym, Literal(Constant(isSpecializedInstance)).setType(BooleanClass.tpe)).setType(NoType) } @@ -1716,9 +1699,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { atPos(pos) { (receiver /: argss) (Apply) } } - /** Concrete methods that use a specialized type, or override such methods. */ - private val concreteSpecMethods = new mutable.HashSet[Symbol]() - /** Add method m to the set of symbols for which we need an implementation tree * in the tree transformer. * diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index e2cd0a8402..1655ad09c4 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -128,7 +128,7 @@ abstract class TailCalls extends Transform { * the label field. */ this.label = { - val label = method.newLabel(method.pos, newTermName("_" + method.name)) + val label = method.newLabel(newTermName("_" + method.name), method.pos) val thisParam = method.newSyntheticValueParam(currentClass.typeOfThis) label setInfo MethodType(thisParam :: method.tpe.params, method.tpe.finalResultType) } @@ -144,7 +144,7 @@ abstract class TailCalls extends Transform { def isTransformed = isEligible && accessed def tailrecFailure() = unit.error(failPos, "could not optimize @tailrec annotated " + method + ": " + failReason) - def newThis(pos: Position) = method.newValue(pos, nme.THIS) setInfo currentClass.typeOfThis setFlag SYNTHETIC + def newThis(pos: Position) = method.newValue(nme.THIS, pos, SYNTHETIC) setInfo currentClass.typeOfThis override def toString(): String = ( "" + method.name + " tparams: " + tparams + " tailPos: " + tailPos + diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index adb408f7e4..56d9658377 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -133,11 +133,9 @@ abstract class UnCurry extends InfoTransform /** Return non-local return key for given method */ private def nonLocalReturnKey(meth: Symbol) = - nonLocalReturnKeys.getOrElseUpdate(meth, { - meth.newValue(meth.pos, unit.freshTermName("nonLocalReturnKey")) - .setFlag (SYNTHETIC) - .setInfo (ObjectClass.tpe) - }) + nonLocalReturnKeys.getOrElseUpdate(meth, + meth.newValue(unit.freshTermName("nonLocalReturnKey"), meth.pos, SYNTHETIC) setInfo ObjectClass.tpe + ) /** Generate a non-local return throw with given return expression from given method. * I.e. for the method's non-local return key, generate: @@ -170,7 +168,7 @@ abstract class UnCurry extends InfoTransform private def nonLocalReturnTry(body: Tree, key: Symbol, meth: Symbol) = { localTyper.typed { val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType) - val ex = meth.newValue(body.pos, nme.ex) setInfo extpe + val ex = meth.newValue(nme.ex, body.pos) setInfo extpe val pat = Bind(ex, Typed(Ident(nme.WILDCARD), AppliedTypeTree(Ident(NonLocalReturnControlClass), @@ -255,40 +253,42 @@ abstract class UnCurry extends InfoTransform if (fun1 ne fun) fun1 else { val (formals, restpe) = (targs.init, targs.last) - val anonClass = owner newAnonymousFunctionClass fun.pos setFlag (FINAL | SYNTHETIC | inConstructorFlag) + val anonClass = owner.newAnonymousFunctionClass(fun.pos, inConstructorFlag) def parents = if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe) else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe) anonClass setInfo ClassInfoType(parents, new Scope, anonClass) - val applyMethod = anonClass.newMethod(fun.pos, nme.apply) setFlag FINAL - applyMethod setInfo MethodType(applyMethod newSyntheticValueParams formals, restpe) - anonClass.info.decls enter applyMethod - anonClass.addAnnotation(serialVersionUIDAnnotation) + val applyMethod = anonClass.newMethod(nme.apply, fun.pos, FINAL) + applyMethod setInfoAndEnter MethodType(applyMethod newSyntheticValueParams formals, restpe) + anonClass addAnnotation serialVersionUIDAnnotation fun.vparams foreach (_.symbol.owner = applyMethod) - new ChangeOwnerTraverser(fun.symbol, applyMethod) traverse fun.body + fun.body.changeOwner(fun.symbol -> applyMethod) def missingCaseCall(scrutinee: Tree): Tree = Apply(Select(This(anonClass), nme.missingCase), List(scrutinee)) def applyMethodDef() = { - val body = + val body = localTyper.typedPos(fun.pos) { if (isPartial) gen.mkUncheckedMatch(gen.withDefaultCase(fun.body, missingCaseCall)) else fun.body - DefDef(Modifiers(FINAL), nme.apply, Nil, List(fun.vparams), TypeTree(restpe), body) setSymbol applyMethod + } + // Have to repack the type to avoid mismatches when existentials + // appear in the result - see SI-4869. + val applyResultType = localTyper.packedType(body, applyMethod) + DefDef(Modifiers(FINAL), nme.apply, Nil, List(fun.vparams), TypeTree(applyResultType), body) setSymbol applyMethod } def isDefinedAtMethodDef() = { val isDefinedAtName = { if (anonClass.info.member(nme._isDefinedAt) != NoSymbol) nme._isDefinedAt else nme.isDefinedAt } - val m = anonClass.newMethod(fun.pos, isDefinedAtName) setFlag FINAL - m setInfo MethodType(m newSyntheticValueParams formals, BooleanClass.tpe) - anonClass.info.decls enter m - val vparam = fun.vparams.head.symbol - val idparam = m.paramss.head.head - val substParam = new TreeSymSubstituter(List(vparam), List(idparam)) + val m = anonClass.newMethod(isDefinedAtName, fun.pos, FINAL) + val params = m newSyntheticValueParams formals + m setInfoAndEnter MethodType(params, BooleanClass.tpe) + + val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params) def substTree[T <: Tree](t: T): T = substParam(resetLocalAttrs(t)) // waiting here until we can mix case classes and extractors reliably (i.e., when virtpatmat becomes the default) @@ -516,9 +516,9 @@ abstract class UnCurry extends InfoTransform */ def liftTree(tree: Tree) = { debuglog("lifting tree at: " + (tree.pos)) - val sym = currentOwner.newMethod(tree.pos, unit.freshTermName("liftedTree")) + val sym = currentOwner.newMethod(unit.freshTermName("liftedTree"), tree.pos) sym.setInfo(MethodType(List(), tree.tpe)) - new ChangeOwnerTraverser(currentOwner, sym).traverse(tree) + tree.changeOwner(currentOwner -> sym) localTyper.typedPos(tree.pos)(Block( List(DefDef(sym, List(Nil), tree)), Apply(Ident(sym), Nil) @@ -772,7 +772,7 @@ abstract class UnCurry extends InfoTransform } val forwresult = dd.symbol.tpe.finalResultType val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) => - currentClass.newValueParameter(oldparam.symbol.pos, oldparam.name).setInfo(tp) + currentClass.newValueParameter(oldparam.name, oldparam.symbol.pos).setInfo(tp) ) def mono = MethodType(forwformsyms, forwresult) val forwtype = dd.symbol.tpe match { @@ -781,11 +781,7 @@ abstract class UnCurry extends InfoTransform } // create the symbol - val forwsym = ( - currentClass.newMethod(dd.pos, dd.name) - . setFlag (VARARGS | SYNTHETIC | flatdd.symbol.flags) - . setInfo (forwtype) - ) + val forwsym = currentClass.newMethod(dd.name, dd.pos, VARARGS | SYNTHETIC | flatdd.symbol.flags) setInfo forwtype // create the tree val forwtree = theTyper.typedPos(dd.pos) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 1d9eb9c292..faff4ccab2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -42,11 +42,11 @@ trait Contexts { self: Analyzer => * * - if option `-Yno-imports` is given, nothing is imported * - if the unit is java defined, only `java.lang` is imported - * - if option `-Yno-predef` is given, if the unit has an import of Predef - * among its leading imports, or if the unit is [[scala.ScalaObject]] + * - if option `-Yno-predef` is given, if the unit body has an import of Predef + * among its leading imports, or if the tree is [[scala.ScalaObject]] * or [[scala.Predef]], `Predef` is not imported. */ - protected def rootImports(unit: CompilationUnit, tree: Tree): List[Symbol] = { + protected def rootImports(unit: CompilationUnit): List[Symbol] = { import definitions._ assert(isDefinitionsInitialized, "definitions uninitialized") @@ -56,23 +56,15 @@ trait Contexts { self: Analyzer => else List(JavaLangPackage, ScalaPackage, PredefModule) } - def rootContext(unit: CompilationUnit): Context = - rootContext(unit, EmptyTree, false) - + def rootContext(unit: CompilationUnit): Context = rootContext(unit, EmptyTree, false) + def rootContext(unit: CompilationUnit, tree: Tree): Context = rootContext(unit, tree, false) def rootContext(unit: CompilationUnit, tree: Tree, erasedTypes: Boolean): Context = { import definitions._ var sc = startContext - def addImport(pkg: Symbol) { - assert(pkg ne null) - val qual = gen.mkAttributedStableRef(pkg) - sc = sc.makeNewImport( - Import(qual, List(ImportSelector(nme.WILDCARD, -1, null, -1))) - .setSymbol(NoSymbol.newImport(NoPosition).setFlag(SYNTHETIC).setInfo(ImportType(qual))) - .setType(NoType)) + for (sym <- rootImports(unit)) { + sc = sc.makeNewImport(sym) sc.depth += 1 } - for (imp <- rootImports(unit, tree)) - addImport(imp) val c = sc.make(unit, tree, sc.owner, sc.scope, sc.imports) c.reportAmbiguousErrors = !erasedTypes c.reportGeneralErrors = !erasedTypes @@ -130,6 +122,10 @@ trait Contexts { self: Analyzer => var typingIndentLevel: Int = 0 def typingIndent = " " * typingIndentLevel + def enclClassOrMethod: Context = + if ((owner eq NoSymbol) || (owner.isClass) || (owner.isMethod)) this + else outer.enclClassOrMethod + def undetparamsString = if (undetparams.isEmpty) "" else undetparams.mkString("undetparams=", ", ", "") @@ -207,6 +203,9 @@ trait Contexts { self: Analyzer => c.implicitsEnabled = true c } + + def makeNewImport(sym: Symbol): Context = + makeNewImport(gen.mkWildcardImport(sym)) def makeNewImport(imp: Import): Context = make(unit, imp, owner, scope, new ImportInfo(imp, depth) :: imports) diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 3b90eaeed7..e14f0bcd87 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -45,8 +45,9 @@ trait Implicits { * @return A search result */ def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult = { - printInference("[inferImplicit%s] pt = %s".format( - if (isView) " view" else "", pt) + printInference("[infer %s] %s with pt=%s in %s".format( + if (isView) "view" else "implicit", + tree, pt, context.owner.enclClass) ) printTyping( ptBlock("infer implicit" + (if (isView) " view" else ""), @@ -65,7 +66,7 @@ trait Implicits { printTyping("typing implicit: %s %s".format(tree, context.undetparamsString)) val result = new ImplicitSearch(tree, pt, isView, context.makeImplicit(reportAmbiguous)).bestImplicit - printInference("[inferImplicit] result: " + result) + printInference("[infer implicit] inferred " + result) context.undetparams = context.undetparams filterNot result.subst.from.contains stopTimer(implicitNanos, start) @@ -93,21 +94,13 @@ trait Implicits { private val ManifestSymbols = Set(PartialManifestClass, FullManifestClass, OptManifestClass) - /** Map all type params in given list to WildcardType - * @param tparams The list of type parameters to map - * @param tp The type in which to do the mapping - */ - private def tparamsToWildcards(tparams: List[Symbol], tp: Type) = - if (tparams.isEmpty) tp - else tp.instantiateTypeParams(tparams, tparams map (_ => WildcardType)) - /* Map a polytype to one in which all type parameters and argument-dependent types are replaced by wildcards. * Consider `implicit def b(implicit x: A): x.T = error("")`. We need to approximate DebruijnIndex types * when checking whether `b` is a valid implicit, as we haven't even searched a value for the implicit arg `x`, * so we have to approximate (otherwise it is excluded a priori). */ private def depoly(tp: Type): Type = tp match { - case PolyType(tparams, restpe) => tparamsToWildcards(tparams, ApproximateDependentMap(restpe)) + case PolyType(tparams, restpe) => deriveTypeWithWildcards(tparams)(ApproximateDependentMap(restpe)) case _ => ApproximateDependentMap(tp) } @@ -191,12 +184,10 @@ trait Implicits { */ def memberWildcardType(name: Name, tp: Type) = { val result = refinedType(List(WildcardType), NoSymbol) - var psym = name match { - case x: TypeName => result.typeSymbol.newAbstractType(NoPosition, x) - case x: TermName => result.typeSymbol.newValue(NoPosition, x) + name match { + case x: TermName => result.typeSymbol.newValue(x) setInfoAndEnter tp + case x: TypeName => result.typeSymbol.newAbstractType(x) setInfoAndEnter tp } - psym setInfo tp - result.decls enter psym result } @@ -395,7 +386,6 @@ trait Implicits { * @pre `info.tpe` does not contain an error */ private def typedImplicit(info: ImplicitInfo, ptChecked: Boolean): SearchResult = { - printInference("[typedImplicit] " + info) (context.openImplicits find { case (tp, sym) => sym == tree.symbol && dominates(pt, tp)}) match { case Some(pending) => // println("Pending implicit "+pending+" dominates "+pt+"/"+undetParams) //@MDEBUG @@ -614,16 +604,15 @@ trait Implicits { info.sym.fullLocationString, itree1.symbol.fullLocationString)) else { val tvars = undetParams map freshVar - - if (matchesPt(itree2.tpe, pt.instantiateTypeParams(undetParams, tvars), undetParams)) { - printInference( - ptBlock("matchesPt", - "itree1" -> itree1, - "tvars" -> tvars, - "undetParams" -> undetParams - ) - ) - + def ptInstantiated = pt.instantiateTypeParams(undetParams, tvars) + + printInference("[search] considering %s (pt contains %s) trying %s against pt=%s".format( + if (undetParams.isEmpty) "no tparams" else undetParams.map(_.name).mkString(", "), + typeVarsInType(ptInstantiated) filterNot (_.isGround) match { case Nil => "no tvars" ; case tvs => tvs.mkString(", ") }, + itree2.tpe, pt + )) + + if (matchesPt(itree2.tpe, ptInstantiated, undetParams)) { if (tvars.nonEmpty) printTyping(ptLine("" + info.sym, "tvars" -> tvars, "tvars.constr" -> tvars.map(_.constr))) @@ -637,6 +626,7 @@ trait Implicits { // we must be conservative in leaving type params in undetparams // prototype == WildcardType: want to remove all inferred Nothings val AdjustedTypeArgs(okParams, okArgs) = adjustTypeArgs(undetParams, tvars, targs) + val subst: TreeTypeSubstituter = if (okParams.isEmpty) EmptyTreeTypeSubstituter else { @@ -663,11 +653,10 @@ trait Implicits { } val result = new SearchResult(itree2, subst) incCounter(foundImplicits) - printInference("[typedImplicit1] SearchResult: " + result) + printInference("[success] found %s for pt %s".format(result, ptInstantiated)) result } - else fail("incompatible: %s does not match expected type %s".format( - itree2.tpe, pt.instantiateTypeParams(undetParams, tvars))) + else fail("incompatible: %s does not match expected type %s".format(itree2.tpe, ptInstantiated)) } } catch { @@ -786,16 +775,11 @@ trait Implicits { // most frequent one first matches sortBy (x => if (isView) -x.useCountView else -x.useCountArg) } - def eligibleString = { - val args = List( - "search" -> pt, - "target" -> tree, - "isView" -> isView - ) ++ eligible.map("eligible" -> _) - - ptBlock("Implicit search in " + context, args: _*) - } - printInference(eligibleString) + if (eligible.nonEmpty) + printInference("[search%s] %s with pt=%s in %s, eligible:\n %s".format( + if (isView) " view" else "", + tree, pt, context.owner.enclClass, eligible.mkString("\n ")) + ) /** Faster implicit search. Overall idea: * - prune aggressively diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 295b66b17f..9db291a306 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -138,6 +138,9 @@ trait Infer { def solvedTypes(tvars: List[TypeVar], tparams: List[Symbol], variances: List[Int], upper: Boolean, depth: Int): List[Type] = { + if (tvars.nonEmpty) + printInference("[solve types] solving for " + tparams.map(_.name).mkString(", ") + " in " + tvars.mkString(", ")) + if (!solve(tvars, tparams, variances, upper, depth)) { // no panic, it's good enough to just guess a solution, we'll find out // later whether it works. *ZAP* @M danger, Will Robinson! this means @@ -363,10 +366,7 @@ trait Infer { def makeFullyDefined(tp: Type): Type = { val tparams = new ListBuffer[Symbol] def addTypeParam(bounds: TypeBounds): Type = { - val tparam = - context.owner.newAbstractType(context.tree.pos.focus, newTypeName("_"+tparams.size)) - .setFlag(EXISTENTIAL) - .setInfo(bounds) + val tparam = context.owner.newExistential(newTypeName("_"+tparams.size), context.tree.pos.focus) setInfo bounds tparams += tparam tparam.tpe } @@ -553,18 +553,6 @@ trait Infer { throw new NoInstance("parameter lists differ in length") val restpeInst = restpe.instantiateTypeParams(tparams, tvars) - printInference( - ptBlock("methTypeArgs", - "tparams" -> tparams, - "formals" -> formals, - "restpe" -> restpe, - "restpeInst" -> restpeInst, - "argtpes" -> argtpes, - "pt" -> pt, - "tvars" -> tvars, - "constraints" -> tvars.map(_.constr) - ) - ) // first check if typevars can be fully defined from the expected type. // The return value isn't used so I'm making it obvious that this side @@ -602,17 +590,7 @@ trait Infer { tvars, tparams, tparams map varianceInTypes(formals), false, lubDepth(formals) max lubDepth(argtpes) ) - val result = adjustTypeArgs(tparams, tvars, targs, restpe) - - printInference( - ptBlock("methTypeArgs result", - "tvars" -> tvars, - "constraints" -> tvars.map(_.constr), - "targs" -> targs, - "adjusted type args" -> result - ) - ) - result + adjustTypeArgs(tparams, tvars, targs, restpe) } private[typechecker] def followApply(tp: Type): Type = tp match { @@ -1097,15 +1075,6 @@ trait Infer { def inferMethodInstance(fn: Tree, undetparams: List[Symbol], args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match { case MethodType(params0, _) => - printInference( - ptBlock("inferMethodInstance", - "fn" -> fn, - "undetparams" -> undetparams, - "args" -> args, - "pt0" -> pt0 - ) - ) - try { val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 val formals = formalTypes(params0 map (_.tpe), args.length) @@ -1115,11 +1084,19 @@ trait Infer { val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt) + printInference("[infer method] solving for %s in %s based on (%s)%s (%s)".format( + undetparams.map(_.name).mkString(", "), + fn.tpe, + argtpes.mkString(", "), + restpe, + (okparams map (_.name), okargs).zipped.map(_ + "=" + _).mkString("solved: ", ", ", "") + )) + checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ") val treeSubst = new TreeTypeSubstituter(okparams, okargs) treeSubst traverseTrees fn :: args - val result = leftUndet match { + leftUndet match { case Nil => Nil case xs => // #3890 @@ -1129,10 +1106,6 @@ trait Infer { xs1 } - if (result.nonEmpty) - printInference("inferMethodInstance, still undetermined: " + result) - - result } catch ifNoInstance { msg => errorTree(fn, "no type parameters for " + @@ -1143,19 +1116,7 @@ trait Infer { } } - /** Type with all top-level occurrences of abstract types replaced by their bounds */ - def widen(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala ) - case TypeRef(_, sym, _) if sym.isAbstractType => - widen(tp.bounds.hi) - case TypeRef(_, sym, _) if sym.isAliasType => - widen(tp.normalize) - case rtp @ RefinedType(parents, decls) => - copyRefinedType(rtp, parents mapConserve widen, decls) - case AnnotatedType(_, underlying, _) => - widen(underlying) - case _ => - tp - } + def widen(tp: Type): Type = abstractTypesToBounds(tp) /** Substitute free type variables <code>undetparams</code> of type constructor * <code>tree</code> in pattern, given prototype <code>pt</code>. diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index b9264aae55..7f9e56a926 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -2,6 +2,8 @@ package scala.tools.nsc package typechecker import symtab.Flags._ +import scala.tools.nsc.util._ +import scala.reflect.ReflectionUtils trait Macros { self: Analyzer => import global._ @@ -13,6 +15,20 @@ trait Macros { self: Analyzer => owner.info.decl(nme.macroMethodName(mac.name)) } + def macroArgs(tree: Tree): (List[List[Tree]]) = tree match { + case Apply(fn, args) => + macroArgs(fn) :+ args + case TypeApply(fn, args) => + macroArgs(fn) :+ args + case Select(qual, name) if !isStaticMacro(tree.symbol) => + List(List(qual)) + case _ => + List(List()) + } + + private def isStaticMacro(mac: Symbol): Boolean = + mac.owner.isModuleClass + /** * The definition of the method implementing a macro. Example: * Say we have in a class C @@ -33,25 +49,32 @@ trait Macros { self: Analyzer => */ def macroMethDef(mdef: DefDef): Tree = { def paramDef(name: Name, tpt: Tree) = ValDef(Modifiers(PARAM), name, tpt, EmptyTree) - val universeType = TypeTree(ReflectApiUniverse.tpe) - val globParamSec = List(paramDef(nme.glob, universeType)) - def globSelect(name: Name) = Select(Ident(nme.glob), name) + val contextType = TypeTree(ReflectMacroContext.tpe) + val globParamSec = List(paramDef(nme.context, contextType)) + def globSelect(name: Name) = Select(Ident(nme.context), name) def globTree = globSelect(newTypeName("Tree")) def globType = globSelect(newTypeName("Type")) - val thisParamSec = if (mdef.symbol.owner.isModuleClass) List() else List(paramDef(newTermName("_this"), globTree)) + val thisParamSec = if (isStaticMacro(mdef.symbol)) List() else List(paramDef(newTermName("_this"), globTree)) def tparamInMacro(tdef: TypeDef) = paramDef(tdef.name.toTermName, globType) - def vparamInMacro(vdef: ValDef): ValDef = paramDef(vdef.name, globTree) + def vparamInMacro(vdef: ValDef): ValDef = paramDef(vdef.name, vdef.tpt match { + case tpt @ AppliedTypeTree(hk, _) if treeInfo.isRepeatedParamType(tpt) => AppliedTypeTree(hk, List(globTree)) + case _ => globTree + }) def wrapImplicit(tree: Tree) = atPos(tree.pos) { - Block(List(ValDef(Modifiers(IMPLICIT), newTermName("$" + nme.glob), universeType, Ident(nme.glob))), tree) + // implicit hasn't proven useful so far, so I'm disabling it + //val implicitDecl = ValDef(Modifiers(IMPLICIT), nme.contextImplicit, SingletonTypeTree(Ident(nme.context)), Ident(nme.context)) + val importGlob = Import(Ident(nme.context), List(ImportSelector(nme.WILDCARD, -1, null, -1))) + Block(List(importGlob), tree) } + var formals = (mdef.vparamss map (_ map vparamInMacro)) + if (mdef.tparams.nonEmpty) formals = (mdef.tparams map tparamInMacro) :: formals atPos(mdef.pos) { new DefDef( // can't call DefDef here; need to find out why - mods = mdef.mods &~ MACRO, + mods = mdef.mods &~ MACRO &~ OVERRIDE, name = nme.macroMethodName(mdef.name), tparams = List(), - vparamss = globParamSec :: thisParamSec :: (mdef.tparams map tparamInMacro) :: - (mdef.vparamss map (_ map vparamInMacro)), + vparamss = globParamSec :: thisParamSec :: formals, tpt = globTree, wrapImplicit(mdef.rhs)) } @@ -59,11 +82,98 @@ trait Macros { self: Analyzer => def addMacroMethods(templ: Template, namer: Namer): Unit = { for (ddef @ DefDef(mods, _, _, _, _, _) <- templ.body if mods hasFlag MACRO) { - val sym = namer.enterSyntheticSym(util.trace("macro def: ")(macroMethDef(ddef))) - println("added to "+namer.context.owner.enclClass+": "+sym) + val trace = scala.tools.nsc.util.trace when settings.debug.value + val sym = namer.enterSyntheticSym(trace("macro def: ")(macroMethDef(ddef))) + trace("added to "+namer.context.owner.enclClass+": ")(sym) } } - def macroExpand(tree: Tree): Tree = ??? + lazy val mirror = new scala.reflect.runtime.Mirror { + lazy val libraryClassLoader = { + val classpath = global.classPath.asURLs + ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader) + } + + override def defaultReflectiveClassLoader() = libraryClassLoader + } + + class MacroExpandError(val msg: String) extends Exception(msg) -}
\ No newline at end of file + /** Return optionally address of companion object and implementation method symbol + * of given macro; or None if implementation classfile cannot be loaded or does + * not contain the macro implementation. + */ + def macroImpl(mac: Symbol): Option[(AnyRef, mirror.Symbol)] = { + try { + val mmeth = macroMeth(mac) + if (mmeth == NoSymbol) None + else { + val receiverClass: mirror.Symbol = mirror.classWithName(mmeth.owner.fullName) + val receiverObj = receiverClass.companionModule + if (receiverObj == NoSymbol) None + else { + val receiver = mirror.getCompanionObject(receiverClass) + val rmeth = receiverObj.info.member(mirror.newTermName(mmeth.name.toString)) + Some((receiver, rmeth)) + } + } + } catch { + case ex: ClassNotFoundException => + None + } + } + + /** Return result of macro expansion. + * Or, if that fails, and the macro overrides a method return + * tree that calls this method instead of the macro. + */ + def macroExpand(tree: Tree): Any = { + val macroDef = tree.symbol + macroImpl(macroDef) match { + case Some((receiver, rmeth)) => + val argss = List(global) :: macroArgs(tree) + val paramss = macroMeth(macroDef).paramss + val rawArgss = for ((as, ps) <- argss zip paramss) yield { + if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1) + else as + } + val rawArgs: Seq[Any] = rawArgss.flatten + try { + mirror.invoke(receiver, rmeth, rawArgs: _*) + } catch { + case ex => + val realex = ReflectionUtils.unwrapThrowable(ex) + val stacktrace = new java.io.StringWriter() + realex.printStackTrace(new java.io.PrintWriter(stacktrace)) + val msg = System.getProperty("line.separator") + stacktrace + throw new MacroExpandError("exception during macro expansion: " + msg) + } + case None => + val trace = scala.tools.nsc.util.trace when settings.debug.value + def notFound() = throw new MacroExpandError("macro implementation not found: " + macroDef.name) + def fallBackToOverridden(tree: Tree): Tree = { + tree match { + case Select(qual, name) if (macroDef.isMacro) => + macroDef.allOverriddenSymbols match { + case first :: others => + return Select(qual, name) setPos tree.pos setSymbol first + case _ => + trace("macro is not overridden: ")(tree) + notFound() + } + case Apply(fn, args) => + Apply(fallBackToOverridden(fn), args) setPos tree.pos + case TypeApply(fn, args) => + TypeApply(fallBackToOverridden(fn), args) setPos tree.pos + case _ => + trace("unexpected tree in fallback: ")(tree) + notFound() + } + } + val tree1 = fallBackToOverridden(tree) + trace("falling back to ")(tree1) + currentRun.macroExpansionFailed = true + tree1 + } + } +} diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 62393befd2..29dffd99d6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -125,11 +125,7 @@ trait MethodSynthesis { def keepClean = false // whether annotations whose definitions are not meta-annotated should be kept. def validate() { } def createAndEnterSymbol(): Symbol = { - val sym = ( - owner.newMethod(tree.pos.focus, name) - setFlag tree.mods.flags & flagsMask - setFlag flagsExtra - ) + val sym = owner.newMethod(name, tree.pos.focus, (tree.mods.flags & flagsMask) | flagsExtra) setPrivateWithin(tree, sym) enterInScope(sym) sym setInfo completer(sym) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 200191fa13..e04d89047b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -293,23 +293,22 @@ trait Namers extends MethodSynthesis { private def createMemberSymbol(tree: MemberDef, name: Name, mask: Long): Symbol = { val pos = tree.pos val isParameter = tree.mods.isParameter - val sym = tree match { - case TypeDef(_, _, _, _) if isParameter => owner.newTypeParameter(pos, name.toTypeName) - case TypeDef(_, _, _, _) => owner.newAliasType(pos, name.toTypeName) - case DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => owner.newConstructor(pos) - case DefDef(_, _, _, _, _, _) => owner.newMethod(pos, name.toTermName) - case ClassDef(_, _, _, _) => owner.newClass(pos, name.toTypeName) - case ModuleDef(_, _, _) => owner.newModule(pos, name) - case ValDef(_, _, _, _) if isParameter => owner.newValueParameter(pos, name) + val flags = tree.mods.flags & mask + + tree match { + case TypeDef(_, _, _, _) if isParameter => owner.newTypeParameter(name.toTypeName, pos, flags) + case TypeDef(_, _, _, _) => owner.newTypeSymbol(name.toTypeName, pos, flags) + case DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => owner.newConstructor(pos, flags) + case DefDef(_, _, _, _, _, _) => owner.newMethod(name.toTermName, pos, flags) + case ClassDef(_, _, _, _) => owner.newClassSymbol(name.toTypeName, pos, flags) + case ModuleDef(_, _, _) => owner.newModule(name, pos, flags) + case ValDef(_, _, _, _) if isParameter => owner.newValueParameter(name, pos, flags) case PackageDef(pid, _) => createPackageSymbol(pos, pid) - case ValDef(_, _, _, _) => owner.newValue(pos, name) + case ValDef(_, _, _, _) => owner.newValue(name, pos, flags) } - sym setFlag (tree.mods.flags & mask) } - private def createFieldSymbol(tree: ValDef): TermSymbol = ( - owner.newValue(tree.pos, nme.getterToLocal(tree.name)) - setFlag tree.mods.flags & FieldFlags | PrivateLocal - ) + private def createFieldSymbol(tree: ValDef): TermSymbol = + owner.newValue(nme.getterToLocal(tree.name), tree.pos, tree.mods.flags & FieldFlags | PrivateLocal) private def createImportSymbol(tree: Tree) = NoSymbol.newImport(tree.pos) setInfo completerOf(tree) @@ -325,7 +324,7 @@ trait Namers extends MethodSynthesis { if (existing.isPackage && pkgOwner == existing.owner) existing else { - val pkg = pkgOwner.newPackage(pos, pid.name.toTermName) + val pkg = pkgOwner.newPackage(pid.name.toTermName, pos) val pkgClass = pkg.moduleClass val pkgClassInfo = new PackageClassInfoType(newPackageScope(pkgClass), pkgClass) @@ -579,7 +578,7 @@ trait Namers extends MethodSynthesis { // via "x$lzy" as can be seen in test #3927. val sym = ( if (owner.isClass) createFieldSymbol(tree) - else owner.newValue(tree.pos, tree.name append nme.LAZY_LOCAL) setFlag tree.mods.flags resetFlag IMPLICIT + else owner.newValue(tree.name append nme.LAZY_LOCAL, tree.pos, tree.mods.flags & ~IMPLICIT) ) enterValSymbol(tree, sym setFlag MUTABLE setLazyAccessor lazyAccessor) } @@ -843,10 +842,10 @@ trait Namers extends MethodSynthesis { Namers.this.classOfModuleClass get clazz foreach { cdefRef => val cdef = cdefRef() if (cdef.mods.isCase) addApplyUnapply(cdef, templateNamer) - addMacroMethods(cdef.impl, templateNamer) + if (settings.Xmacros.value) addMacroMethods(cdef.impl, templateNamer) classOfModuleClass -= clazz } - addMacroMethods(templ, templateNamer) + if (settings.Xmacros.value) addMacroMethods(templ, templateNamer) } // add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because @@ -1391,10 +1390,9 @@ trait Namers extends MethodSynthesis { ) if (sym hasAnnotation NativeAttr) sym resetFlag DEFERRED - else if (!symbolAllowsDeferred && ownerRequiresConcrete) { + else if (!symbolAllowsDeferred && ownerRequiresConcrete) fail("only classes can have declared but undefined members" + abstractVarMessage(sym)) - sym resetFlag DEFERRED - } + checkWithDeferred(PRIVATE) checkWithDeferred(FINAL) } diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index a8dfea02ec..79cb211215 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -154,10 +154,9 @@ trait NamesDefaults { self: Analyzer => // never used for constructor calls, they always have a stable qualifier def blockWithQualifier(qual: Tree, selected: Name) = { - val sym = blockTyper.context.owner.newValue(qual.pos, unit.freshTermName("qual$")) - .setInfo(qual.tpe) - blockTyper.context.scope.enter(sym) - val vd = atPos(sym.pos)(ValDef(sym, qual).setType(NoType)) + val sym = blockTyper.context.owner.newValue(unit.freshTermName("qual$"), qual.pos) setInfo qual.tpe + blockTyper.context.scope enter sym + val vd = atPos(sym.pos)(ValDef(sym, qual) setType NoType) var baseFunTransformed = atPos(baseFun.pos.makeTransparent) { // don't use treeCopy: it would assign opaque position. @@ -269,7 +268,7 @@ trait NamesDefaults { self: Analyzer => case _ => (seqType(arg.tpe), true) } else (arg.tpe, false) - val s = context.owner.newValue(arg.pos, unit.freshTermName("x$")) + val s = context.owner.newValue(unit.freshTermName("x$"), arg.pos) val valType = if (byName) functionType(List(), argTpe) else if (repeated) argTpe else argTpe diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index 440db4300c..ed185c27d6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -53,7 +53,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => import typeDebug.{ ptTree, ptBlock, ptLine } def solveContextBound(contextBoundTp: Type): (Tree, Type) = { - val solSym = NoSymbol.newTypeParameter(NoPosition, newTypeName("SolveImplicit$")) + val solSym = NoSymbol.newTypeParameter(newTypeName("SolveImplicit$")) val param = solSym.setInfo(contextBoundTp.typeSymbol.typeParams(0).info.cloneInfo(solSym)) // TypeBounds(NothingClass.typeConstructor, baseTp) val pt = appliedType(contextBoundTp, List(param.tpeHK)) val savedUndets = context.undetparams @@ -1128,62 +1128,48 @@ defined class Foo */ // } // } - def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = if (optimizingCodeGen) { - def unfold(tms: List[TreeMaker], currLabel: Option[Symbol] = None, nextLabel: Option[Symbol] = None): List[CaseDef] = tms match { - // constant - case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => import CODE._ - @inline - def substedBody = btm.substitution(body) - val labelledBody = currLabel match { - case None => substedBody // currLabel.isEmpty implies nextLabel.isEmpty - case Some(myLabel) => - LabelDef(myLabel, Nil, - nextLabel match { - case None => substedBody - case Some(next) => ID(next) APPLY () - } - ) - } - List(CaseDef(const, EmptyTree, labelledBody)) - - // alternatives - case AlternativesTreeMaker(_, altss, _) :: bodyTm :: Nil => // assert(currLabel.isEmpty && nextLabel.isEmpty) - val labels = altss map { alts => - Some(freshSym(NoPosition, MethodType(Nil, pt), "$alt$") setFlag (METHOD | LABEL)) - } - - val caseDefs = (altss, labels, labels.tail :+ None).zipped.map { case (alts, currLabel, nextLabel) => - unfold(alts :+ bodyTm, currLabel, nextLabel) - } - - if (caseDefs exists (_.isEmpty)) Nil - else caseDefs.flatten - - case _ => Nil // failure - } + def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Tree] = if (!optimizingCodeGen) None else { + def sequence[T](xs: List[Option[T]]): Option[List[T]] = + if (xs exists (_.isEmpty)) None else Some(xs.flatten) val caseDefs = cases map { makers => removeSubstOnly(makers) match { // default case (don't move this to unfold, as it may only occur on the top level, not as an alternative -- well, except in degenerate matches) case (btm@BodyTreeMaker(body, _)) :: Nil => - List(CaseDef(Ident(nme.WILDCARD), EmptyTree, btm.substitution(body))) - case nonTrivialMakers => - unfold(nonTrivialMakers) + Some(CaseDef(Ident(nme.WILDCARD), EmptyTree, btm.substitution(body))) + // constant + case (EqualityTestTreeMaker(_, const@SwitchablePattern(), _)) :: (btm@BodyTreeMaker(body, _)) :: Nil => import CODE._ + Some(CaseDef(const, EmptyTree, btm.substitution(body))) + // alternatives + case AlternativesTreeMaker(_, altss, _) :: (btm@BodyTreeMaker(body, _)) :: Nil => // assert(currLabel.isEmpty && nextLabel.isEmpty) + val caseConstants = altss map { + case EqualityTestTreeMaker(_, const@SwitchablePattern(), _) :: Nil => + Some(const) + case _ => + None + } + + sequence(caseConstants) map { contants => + val substedBody = btm.substitution(body) + CaseDef(Alternative(contants), EmptyTree, substedBody) + } + case _ => + None //failure (can't translate pattern to a switch) } } - if (caseDefs exists (_.isEmpty)) None - else { import CODE._ + sequence(caseDefs) map { caseDefs => + import CODE._ val matcher = BLOCK( VAL(scrutSym) === scrut, // TODO: type test for switchable type if patterns allow switch but the scrutinee doesn't - Match(REF(scrutSym), caseDefs.flatten) // match on scrutSym, not scrut to avoid duplicating scrut + Match(REF(scrutSym), caseDefs) // match on scrutSym, not scrut to avoid duplicating scrut ) // matcher filter (tree => tree.tpe == null) foreach println // treeBrowser browse matcher - Some(matcher) // set type to avoid recursion in typedMatch + matcher // set type to avoid recursion in typedMatch } - } else None + } def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): List[List[TreeMaker]] = doCSE(prevBinder, doDCE(prevBinder, cases, pt), pt) @@ -1245,7 +1231,7 @@ defined class Foo */ } t match { case Function(_, _) if t.symbol == NoSymbol => - t.symbol = currentOwner.newValue(t.pos, nme.ANON_FUN_NAME).setFlag(SYNTHETIC).setInfo(NoType) + t.symbol = currentOwner.newAnonymousFunctionValue(t.pos) // println("new symbol for "+ (t, t.symbol.ownerChain)) case Function(_, _) if (t.symbol.owner == NoSymbol) || (t.symbol.owner == origOwner) => // println("fundef: "+ (t, t.symbol.ownerChain, currentOwner.ownerChain)) @@ -1377,19 +1363,19 @@ defined class Foo */ @inline private def dontStore(tp: Type) = (tp.typeSymbol eq UnitClass) || (tp.typeSymbol eq NothingClass) lazy val keepGoing = freshSym(NoPosition, BooleanClass.tpe, "keepGoing") setFlag MUTABLE lazy val matchRes = freshSym(NoPosition, AnyClass.tpe, "matchRes") setFlag MUTABLE - override def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type, hasDefault: Boolean) = matcher match { - case Function(List(x: ValDef), body) => - matchRes.info = if (resTp ne NoType) resTp.widen else AnyClass.tpe // we don't always know resTp, and it might be AnyVal, in which case we can't assign NULL - if (dontStore(resTp)) matchRes resetFlag MUTABLE // don't assign to Unit-typed var's, in fact, make it a val -- conveniently also works around SI-5245 - BLOCK( - VAL(zeroSym) === REF(NoneModule), // TODO: can we just get rid of explicitly emitted zero? don't know how to do that as a local rewrite... - VAL(x.symbol) === scrut, // reuse the symbol of the function's argument to avoid creating a fresh one and substituting it for x.symbol in body -- the owner structure is repaired by fixerUpper - VAL(matchRes) === mkZero(matchRes.info), // must cast to deal with GADT typing, hence the private mkZero above - VAL(keepGoing) === TRUE, - body, - if(hasDefault) REF(matchRes) - else (IF (REF(keepGoing)) THEN MATCHERROR(REF(x.symbol)) ELSE REF(matchRes)) - ) + override def runOrElse(scrut: Tree, matcher: Tree, scrutTp: Type, resTp: Type, hasDefault: Boolean) = { + val Function(List(x: ValDef), body) = matcher + matchRes.info = if (resTp ne NoType) resTp.widen else AnyClass.tpe // we don't always know resTp, and it might be AnyVal, in which case we can't assign NULL + if (dontStore(resTp)) matchRes resetFlag MUTABLE // don't assign to Unit-typed var's, in fact, make it a val -- conveniently also works around SI-5245 + BLOCK( + VAL(zeroSym) === REF(NoneModule), // TODO: can we just get rid of explicitly emitted zero? don't know how to do that as a local rewrite... + VAL(x.symbol) === scrut, // reuse the symbol of the function's argument to avoid creating a fresh one and substituting it for x.symbol in body -- the owner structure is repaired by fixerUpper + VAL(matchRes) === mkZero(matchRes.info), // must cast to deal with GADT typing, hence the private mkZero above + VAL(keepGoing) === TRUE, + body, + if(hasDefault) REF(matchRes) + else (IF (REF(keepGoing)) THEN MATCHERROR(REF(x.symbol)) ELSE REF(matchRes)) + ) } // only used to wrap the RHS of a body diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 8f9cd46611..112aa47114 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -171,8 +171,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R def varargBridge(member: Symbol, bridgetpe: Type): Tree = { log("Generating varargs bridge for " + member.fullLocationString + " of type " + bridgetpe) - val bridge = member.cloneSymbolImpl(clazz) - .setPos(clazz.pos).setFlag(member.flags | VBRIDGE) + val bridge = member.cloneSymbolImpl(clazz, member.flags | VBRIDGE) setPos clazz.pos bridge.setInfo(bridgetpe.cloneInfo(bridge)) clazz.info.decls enter bridge @@ -332,21 +331,22 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R // return if we already checked this combination elsewhere if (member.owner != clazz) { - if ((member.owner isSubClass other.owner) && (member.isDeferred || !other.isDeferred)) { + def deferredCheck = member.isDeferred || !other.isDeferred + def subOther(s: Symbol) = s isSubClass other.owner + def subMember(s: Symbol) = s isSubClass member.owner + + if (subOther(member.owner) && deferredCheck) { //Console.println(infoString(member) + " shadows1 " + infoString(other) " in " + clazz);//DEBUG - return; + return + } + if (clazz.parentSymbols exists (p => subOther(p) && subMember(p) && deferredCheck)) { + //Console.println(infoString(member) + " shadows2 " + infoString(other) + " in " + clazz);//DEBUG + return + } + if (clazz.parentSymbols forall (p => subOther(p) == subMember(p))) { + //Console.println(infoString(member) + " shadows " + infoString(other) + " in " + clazz);//DEBUG + return } - if (clazz.info.parents exists (parent => - (parent.typeSymbol isSubClass other.owner) && (parent.typeSymbol isSubClass member.owner) && - (member.isDeferred || !other.isDeferred))) { - //Console.println(infoString(member) + " shadows2 " + infoString(other) + " in " + clazz);//DEBUG - return; - } - if (clazz.info.parents forall (parent => - (parent.typeSymbol isSubClass other.owner) == (parent.typeSymbol isSubClass member.owner))) { - //Console.println(infoString(member) + " shadows " + infoString(other) + " in " + clazz);//DEBUG - return; - } } /** Is the intersection between given two lists of overridden symbols empty? @@ -444,6 +444,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R // check a type alias's RHS corresponds to its declaration // this overlaps somewhat with validateVariance if(member.isAliasType) { + // println("checkKindBounds" + ((List(member), List(memberTp.normalize), self, member.owner))) val kindErrors = typer.infer.checkKindBounds(List(member), List(memberTp.normalize), self, member.owner) if(!kindErrors.isEmpty) @@ -672,9 +673,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } } } - val parents = bc.info.parents - if (!parents.isEmpty && parents.head.typeSymbol.hasFlag(ABSTRACT)) - checkNoAbstractDecls(parents.head.typeSymbol) + if (bc.superClass hasFlag ABSTRACT) + checkNoAbstractDecls(bc.superClass) } checkNoAbstractMembers() @@ -1166,12 +1166,9 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } def createStaticModuleAccessor() = atPhase(phase.next) { val method = ( - sym.owner.newMethod(sym.pos, sym.name.toTermName) - setFlag (sym.flags | STABLE) - resetFlag MODULE - setInfo NullaryMethodType(sym.moduleClass.tpe) + sym.owner.newMethod(sym.name.toTermName, sym.pos, (sym.flags | STABLE) & ~MODULE) + setInfoAndEnter NullaryMethodType(sym.moduleClass.tpe) ) - sym.owner.info.decls enter method localTyper.typedPos(tree.pos)(gen.mkModuleAccessDef(method, sym)) } def createInnerModuleAccessor(vdef: Tree) = List( diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index cde531adc1..4e4fbe35cb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -97,18 +97,13 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT var superAcc = clazz.info.decl(supername).suchThat(_.alias == sym) if (superAcc == NoSymbol) { debuglog("add super acc " + sym + sym.locationString + " to `" + clazz);//debug - superAcc = - clazz.newMethod(tree.pos, supername) - .setFlag(SUPERACCESSOR | PRIVATE) - .setAlias(sym) + superAcc = clazz.newMethod(supername, tree.pos, SUPERACCESSOR | PRIVATE) setAlias sym var superAccTpe = clazz.thisType.memberType(sym) if (sym.isModule && !sym.isMethod) { // the super accessor always needs to be a method. See #231 superAccTpe = NullaryMethodType(superAccTpe) } - superAcc.setInfo(superAccTpe.cloneInfo(superAcc)) - //println("creating super acc "+superAcc+":"+superAcc.tpe)//DEBUG - clazz.info.decls enter superAcc + superAcc setInfoAndEnter (superAccTpe cloneInfo superAcc) storeAccessorDefinition(clazz, DefDef(superAcc, EmptyTree)) } atPos(sup.pos) { @@ -312,14 +307,12 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT memberType.cloneInfo(protAcc).asSeenFrom(qual.tpe, sym.owner)) } - var protAcc = clazz.info.decl(accName).suchThat(s => s == NoSymbol || s.tpe =:= accType(s)) - if (protAcc == NoSymbol) { - protAcc = clazz.newMethod(tree.pos, nme.protName(sym.originalName)) - protAcc.setInfo(accType(protAcc)) - clazz.info.decls.enter(protAcc); + val protAcc = clazz.info.decl(accName).suchThat(s => s == NoSymbol || s.tpe =:= accType(s)) orElse { + val newAcc = clazz.newMethod(nme.protName(sym.originalName), tree.pos) + newAcc setInfoAndEnter accType(newAcc) - val code = DefDef(protAcc, { - val (receiver :: _) :: tail = protAcc.paramss + val code = DefDef(newAcc, { + val (receiver :: _) :: tail = newAcc.paramss val base: Tree = Select(Ident(receiver), sym) val allParamTypes = mapParamss(sym)(_.tpe) val args = map2(tail, allParamTypes)((params, tpes) => map2(params, tpes)(makeArg(_, receiver, _))) @@ -328,12 +321,15 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT debuglog("" + code) storeAccessorDefinition(clazz, code) + newAcc } - var res: Tree = atPos(tree.pos) { - if (targs.head == EmptyTree) - Apply(Select(This(clazz), protAcc), List(qual)) - else - Apply(TypeApply(Select(This(clazz), protAcc), targs), List(qual)) + val selection = Select(This(clazz), protAcc) + def mkApply(fn: Tree) = Apply(fn, qual :: Nil) + val res = atPos(tree.pos) { + targs.head match { + case EmptyTree => mkApply(selection) + case _ => mkApply(TypeApply(selection, targs)) + } } debuglog("Replaced " + tree + " with " + res) if (hasArgs) localTyper.typedOperator(res) else localTyper.typed(res) @@ -371,25 +367,21 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val clazz = hostForAccessorOf(field, currentOwner.enclClass) assert(clazz != NoSymbol, field) debuglog("Decided for host class: " + clazz) + val accName = nme.protSetterName(field.originalName) - var protAcc = clazz.info.decl(accName) - if (protAcc == NoSymbol) { - protAcc = clazz.newMethod(field.pos, nme.protSetterName(field.originalName)) - protAcc.setInfo(MethodType(protAcc.newSyntheticValueParams(List(clazz.typeOfThis, field.tpe)), - UnitClass.tpe)) - clazz.info.decls.enter(protAcc) - val code = DefDef(protAcc, { - val obj :: value :: Nil = protAcc.paramss.head - atPos(tree.pos) { - Assign( - Select(Ident(obj), field.name), - Ident(value)) - } - }) - debuglog("" + code) - storeAccessorDefinition(clazz, code) + val protectedAccessor = clazz.info decl accName orElse { + val protAcc = clazz.newMethod(accName, field.pos) + val paramTypes = List(clazz.typeOfThis, field.tpe) + val params = protAcc newSyntheticValueParams paramTypes + val accessorType = MethodType(params, UnitClass.tpe) + + protAcc setInfoAndEnter accessorType + val obj :: value :: Nil = params + storeAccessorDefinition(clazz, DefDef(protAcc, Assign(Select(Ident(obj), field.name), Ident(value)))) + + protAcc } - atPos(tree.pos)(Select(This(clazz), protAcc)) + atPos(tree.pos)(Select(This(clazz), protectedAccessor)) } /** Does `sym` need an accessor when accessed from `currentOwner`? diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 92e4e257bf..4e986dc5aa 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -110,12 +110,12 @@ trait SyntheticMethods extends ast.TreeDSL { } private def createInternal(name: Name, f: Symbol => Tree, info: Type): Tree = { - val m = clazz.newMethod(clazz.pos.focus, name.toTermName) + val m = clazz.newMethod(name.toTermName, clazz.pos.focus) m setInfo info finishMethod(m, f) } private def createInternal(name: Name, f: Symbol => Tree, infoFn: Symbol => Type): Tree = { - val m = clazz.newMethod(clazz.pos.focus, name.toTermName) + val m = clazz.newMethod(name.toTermName, clazz.pos.focus) m setInfo infoFn(m) finishMethod(m, f) } @@ -282,7 +282,7 @@ trait SyntheticMethods extends ast.TreeDSL { def argsBody: Tree = { val otherName = context.unit.freshTermName(clazz.name + "$") - val otherSym = m.newValue(m.pos, otherName) setInfo clazz.tpe setFlag SYNTHETIC + val otherSym = m.newValue(otherName, m.pos, SYNTHETIC) setInfo clazz.tpe val pairwise = accessors map (acc => fn(Select(This(clazz), acc), acc.tpe member nme.EQ, Select(Ident(otherSym), acc))) val canEq = gen.mkMethodCall(otherSym, nme.canEqual_, Nil, List(This(clazz))) def block = Block(ValDef(otherSym, thatCast), AND(pairwise :+ canEq: _*)) diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 080a802272..fe3ceafa2d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -181,10 +181,7 @@ trait TypeDiagnostics { val getter = if (member.isSetter) member.getter(member.owner) else member val flags = if (getter.setter(member.owner) != NoSymbol) DEFERRED | MUTABLE else DEFERRED - ( getter.owner.newValue(getter.pos, getter.name.toTermName) - setInfo getter.tpe.resultType - setFlag flags - ) + getter.owner.newValue(getter.name.toTermName, getter.pos, flags) setInfo getter.tpe.resultType } def treeSymTypeMsg(tree: Tree): String = { @@ -497,6 +494,11 @@ trait TypeDiagnostics { def cyclicReferenceMessage(sym: Symbol, tree: Tree) = condOpt(tree) { case ValDef(_, _, tpt, _) if tpt.tpe == null => "recursive "+sym+" needs type" case DefDef(_, _, _, _, tpt, _) if tpt.tpe == null => List(cyclicAdjective(sym), sym, "needs result type") mkString " " + case Import(expr, selectors) => + ( "encountered unrecoverable cycle resolving import." + + "\nNote: this is often due in part to a class depending on a definition nested within its companion." + + "\nIf applicable, you may wish to try moving some members into another object." + ) } /** Report a type error. @@ -511,7 +513,11 @@ trait TypeDiagnostics { ex match { case CyclicReference(sym, info: TypeCompleter) => - contextError(ex.pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage()) + val pos = info.tree match { + case Import(expr, _) => expr.pos + case _ => ex.pos + } + contextError(pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage()) if (sym == ObjectClass) throw new FatalError("cannot redefine root "+sym) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5ccf27ded9..216ad6cd4c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -911,7 +911,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } if (tree.isType) adaptType() - else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) + else if (inExprModeButNot(mode, FUNmode) && tree.symbol != null && tree.symbol.isMacro && !tree.isDef) { + val tree1 = expandMacro(tree) + if (tree1.isErroneous) tree1 else typed(tree1, mode, pt) + } else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) adaptConstrPattern() else if (inAllModes(mode, EXPRmode | FUNmode) && !tree.tpe.isInstanceOf[MethodType] && @@ -1659,7 +1662,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case Some(repl) => silent(_.typedTypeConstructor(stringParser(repl).typ())) match { case tpt: Tree => - val alias = enclClass.newAliasType(useCase.pos, name.toTypeName) + val alias = enclClass.newAliasType(name.toTypeName, useCase.pos) val tparams = cloneSymbolsAtOwner(tpt.tpe.typeSymbol.typeParams, alias) alias setInfo typeFun(tparams, appliedType(tpt.tpe, tparams map (_.tpe))) context.scope.enter(alias) @@ -1793,7 +1796,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ldef @ LabelDef(_, _, _) => if (ldef.symbol == NoSymbol) ldef.symbol = namer.enterInScope( - context.owner.newLabel(ldef.pos, ldef.name) setInfo MethodType(List(), UnitClass.tpe)) + context.owner.newLabel(ldef.name, ldef.pos) setInfo MethodType(List(), UnitClass.tpe)) case _ => } } @@ -1814,7 +1817,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } else { context.scope.unlink(ldef.symbol) val sym2 = namer.enterInScope( - context.owner.newLabel(ldef.pos, ldef.name) setInfo MethodType(List(), restpe)) + context.owner.newLabel(ldef.name, ldef.pos) setInfo MethodType(List(), restpe)) val rhs2 = typed(resetAllAttrs(ldef.rhs), restpe) ldef.params foreach (param => param.tpe = param.symbol.tpe) treeCopy.LabelDef(ldef, ldef.name, ldef.params, rhs2) setSymbol sym2 setType restpe @@ -2529,7 +2532,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val unapp = unapplyMember(otpe) val unappType = otpe.memberType(unapp) - val argDummy = context.owner.newValue(fun.pos, nme.SELECTOR_DUMMY) setFlag SYNTHETIC setInfo pt + val argDummy = context.owner.newValue(nme.SELECTOR_DUMMY, fun.pos, SYNTHETIC) setInfo pt val arg = Ident(argDummy) setType pt if (!isApplicableSafe(Nil, unappType, List(pt), WildcardType)) { @@ -2542,7 +2545,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val pattp = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe) // turn any unresolved type variables in freevars into existential skolems - val skolems = freeVars map (fv => newExistentialSkolem(fv, unapplyContext.owner, fv)) + val skolems = freeVars map (fv => unapplyContext.owner.newExistentialSkolem(fv, fv)) arg.tpe = pattp.substSym(freeVars, skolems) argDummy setInfo arg.tpe } @@ -2817,7 +2820,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } val bound = sym.existentialBound val sowner = if (isRawParameter(sym)) context.owner else sym.owner - val quantified = sowner.newExistential(sym.pos, name) + val quantified = sowner.newExistential(name, sym.pos) quantified setInfo bound.cloneInfo(quantified) } @@ -2835,9 +2838,22 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def packSymbols(hidden: List[Symbol], tp: Type): Type = if (hidden.isEmpty) tp else existentialTransform(hidden, tp)(existentialAbstraction) + + def isReferencedFrom(ctx: Context, sym: Symbol): Boolean = + ctx.owner.isTerm && + (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || + { + var ctx1 = ctx.outer + while ((ctx1 != NoContext) && (ctx1.scope eq ctx.scope)) ctx1 = ctx1.outer + (ctx1 != NoContext) && isReferencedFrom(ctx1, sym) + } def isCapturedExistential(sym: Symbol) = - sym hasAllFlags (EXISTENTIAL | CAPTURED) // todo refine this + (sym hasAllFlags (EXISTENTIAL | CAPTURED)) && { + val start = startTimer(isReferencedNanos) + try !isReferencedFrom(context, sym) + finally stopTimer(isReferencedNanos, start) + } def packCaptured(tpe: Type): Type = { val captured = mutable.Set[Symbol]() @@ -3079,7 +3095,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { * */ ( context.owner newLocalDummy (ann.pos) - newValue (ann.pos, nme.self) + newValue (nme.self, ann.pos) setInfo (arg1.tpe.withoutAnnotations) ) } @@ -3120,9 +3136,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (vble == NoSymbol) vble = if (isFullyDefined(pt)) - context.owner.newAliasType(tree.pos, name) setInfo pt + context.owner.newAliasType(name, tree.pos) setInfo pt else - context.owner.newAbstractType(tree.pos, name) setInfo TypeBounds.empty + context.owner.newAbstractType(name, tree.pos) setInfo TypeBounds.empty val rawInfo = vble.rawInfo vble = if (vble.name == tpnme.WILDCARD) context.scope.enter(vble) else namer.enterInScope(vble) @@ -3130,7 +3146,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } def typedBindTerm(name: TermName) = { if (vble == NoSymbol) - vble = context.owner.newValue(tree.pos, name) + vble = context.owner.newValue(name, tree.pos) if (vble.name.toTermName != nme.WILDCARD) { if ((mode & ALTmode) != 0) error(tree.pos, "illegal variable in pattern alternative") @@ -3471,9 +3487,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // (calling typed1 more than once for the same tree) if (checked ne res) typed { atPos(tree.pos)(checked) } else res - } else if ((mode & FUNmode) == 0 && fun2.hasSymbol && fun2.symbol.isMacro) - typed1(macroExpand(res), mode, pt) - else + } else res case ex: TypeError => fun match { @@ -3483,7 +3497,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (treeInfo.isVariableOrGetter(qual1)) { stopTimer(failedOpEqNanos, opeqStart) convertToAssignment(fun, qual1, name, args, ex) - } + } else { stopTimer(failedApplyNanos, appStart) reportTypeError(fun.pos, ex) @@ -3800,11 +3814,31 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { var cx = startingIdentContext while (defSym == NoSymbol && cx != NoContext) { + // !!! Shouldn't the argument to compileSourceFor be cx, not context? + // I can't tell because those methods do nothing in the standard compiler, + // presumably they are overridden in the IDE. currentRun.compileSourceFor(context.asInstanceOf[analyzer.Context], name) pre = cx.enclClass.prefix defEntry = cx.scope.lookupEntry(name) if ((defEntry ne null) && qualifies(defEntry.sym)) { - defSym = defEntry.sym + // Right here is where SI-1987, overloading in package objects, can be + // seen to go wrong. There is an overloaded symbol, but when referring + // to the unqualified identifier from elsewhere in the package, only + // the last definition is visible. So overloading mis-resolves and is + // definition-order dependent, bad things. See run/t1987.scala. + // + // I assume the actual problem involves how/where these symbols are entered + // into the scope. But since I didn't figure out how to fix it that way, I + // catch it here by looking up package-object-defined symbols in the prefix. + if (isInPackageObject(defEntry.sym, pre.typeSymbol)) { + defSym = pre.member(defEntry.sym.name) + if (defSym ne defEntry.sym) { + log("!!! Overloaded package object member resolved incorrectly.\n Discarded: " + + defEntry.sym.defString + "\n Using: " + defSym.defString) + } + } + else + defSym = defEntry.sym } else { cx = cx.enclClass @@ -3897,9 +3931,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // Avoiding some spurious error messages: see SI-2388. if (reporter.hasErrors && (name startsWith tpnme.ANON_CLASS_NAME)) () else { - val similar = ( - // name length check to limit unhelpful suggestions for e.g. "x" and "b1" - if (name.length > 2) { + // This laborious determination arrived at to keep the tests working. + val calcSimilar = ( + name.length > 2 && ( + startingIdentContext.reportGeneralErrors + || startingIdentContext.enclClassOrMethod.reportGeneralErrors + ) + ) + // avoid calculating if we're in "silent" mode. + // name length check to limit unhelpful suggestions for e.g. "x" and "b1" + val similar = { + if (!calcSimilar) "" + else { val allowed = ( startingIdentContext.enclosingContextChain flatMap (ctx => ctx.scope.toList ++ ctx.imports.flatMap(_.allImportedSymbols)) @@ -3912,8 +3955,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { ) similarString("" + name, allowedStrings) } - else "" - ) + } error(tree.pos, "not found: "+decodeWithKind(name, context.owner) + similar) } } @@ -4098,8 +4140,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case tree @ Function(_, _) => if (tree.symbol == NoSymbol) - tree.symbol = context.owner.newValue(tree.pos, nme.ANON_FUN_NAME) - .setFlag(SYNTHETIC).setInfo(NoType) + tree.symbol = context.owner.newAnonymousFunctionValue(tree.pos) + newTyper(context.makeNewScope(tree, tree.symbol)).typedFunction(tree, mode, pt) case Assign(lhs, rhs) => @@ -4413,6 +4455,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } + def expandMacro(tree: Tree): Tree = try { + macroExpand(tree) match { + case t: Tree => t + case t => errorTree(tree, "macros must return a compiler-specific tree; returned class is: " + t.getClass) + } + } catch { + case ex: MacroExpandError => errorTree(tree, ex.msg) + } + def atOwner(owner: Symbol): Typer = newTyper(context.make(context.tree, owner)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index fd6f972ffc..a7cd89621c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -21,7 +21,7 @@ trait Unapplies extends ast.TreeDSL import CODE.{ CASE => _, _ } import treeInfo.{ isRepeatedParamType, isByNameParamType } - private val unapplyParamName = newTermName("x$0") + private val unapplyParamName = nme.x_0 /** returns type list for return type of the extraction */ def unapplyTypeList(ufn: Symbol, ufntpe: Type) = { diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index a1ec90ed3f..53c767be20 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -9,7 +9,30 @@ package util object Position { val tabInc = 8 + + /** Prints the message with the given position indication. */ + def formatMessage(posIn: Position, msg: String, shortenFile: Boolean): String = { + val pos = ( + if (posIn eq null) NoPosition + else if (posIn.isDefined) posIn.inUltimateSource(posIn.source) + else posIn + ) + def file = pos.source.file + def prefix = if (shortenFile) file.name else file.path + + pos match { + case FakePos(fmsg) => fmsg+" "+msg + case NoPosition => msg + case _ => + List( + "%s:%s: %s".format(prefix, pos.line, msg), + pos.lineContent.stripLineEnd, + " " * (pos.column - 1) + "^" + ) mkString "\n" + } + } } + /** The Position class and its subclasses represent positions of ASTs and symbols. * Except for NoPosition and FakePos, every position refers to a SourceFile * and to an offset in the sourcefile (its `point`). For batch compilation, diff --git a/src/compiler/scala/tools/nsc/util/Statistics.scala b/src/compiler/scala/tools/nsc/util/Statistics.scala index 27239b9b9f..f7c27dceb5 100644 --- a/src/compiler/scala/tools/nsc/util/Statistics.scala +++ b/src/compiler/scala/tools/nsc/util/Statistics.scala @@ -20,7 +20,7 @@ class Statistics extends scala.reflect.internal.util.Statistics { val typedSelectCount = new Counter val typerNanos = new Timer val classReadNanos = new Timer - + val failedApplyNanos = new Timer val failedOpEqNanos = new Timer val failedSilentNanos = new Timer @@ -48,6 +48,7 @@ class Statistics extends scala.reflect.internal.util.Statistics { val subtypeImprovCount = new SubCounter(subtypeCount) val subtypeETNanos = new Timer val matchesPtNanos = new Timer + val isReferencedNanos = new Timer val ctr1 = new Counter val ctr2 = new Counter val ctr3 = new Counter @@ -137,6 +138,7 @@ abstract class StatisticsInfo { inform("time spent in failed : "+showRelTyper(failedSilentNanos)) inform(" failed apply : "+showRelTyper(failedApplyNanos)) inform(" failed op= : "+showRelTyper(failedOpEqNanos)) + inform("time spent ref scanning : "+showRelTyper(isReferencedNanos)) inform("micros by tree node : "+showCounts(microsByType)) inform("#visits by tree node : "+showCounts(visitsByType)) val average = new ClassCounts diff --git a/src/compiler/scala/tools/util/EditDistance.scala b/src/compiler/scala/tools/util/EditDistance.scala index 5067dce384..5f152ecabb 100644 --- a/src/compiler/scala/tools/util/EditDistance.scala +++ b/src/compiler/scala/tools/util/EditDistance.scala @@ -7,6 +7,8 @@ package scala.tools package util object EditDistance { + import java.lang.Character.{ toLowerCase => lower } + def similarString(name: String, allowed: TraversableOnce[String]): String = { val suggested = suggestions(name, allowed.toSeq, maxDistance = 1, maxSuggestions = 2) if (suggested.isEmpty) "" @@ -46,7 +48,7 @@ object EditDistance { var j = 1 while (j <= m) { val t_j = t(j - 1) - val cost = if (s_i == t_j) 0 else 1 + val cost = if (lower(s_i) == lower(t_j)) 0 else 1 val c1 = d(i - 1)(j) + 1 val c2 = d(i)(j - 1) + 1 diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index 585dc3fbe8..cea558d2d3 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -215,13 +215,9 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with case ldef @ LabelDef(name, params, rhs) => if (hasAnswerTypeAnn(tree.tpe)) { - val sym = currentOwner.newMethod(tree.pos, name) - .setInfo(ldef.symbol.info) - .setFlag(Flags.SYNTHETIC) - - val rhs1 = new TreeSymSubstituter(List(ldef.symbol), List(sym)).transform(rhs) - val rhsVal = transExpr(rhs1, None, getAnswerTypeAnn(tree.tpe)) - new ChangeOwnerTraverser(currentOwner, sym) traverse rhsVal + val sym = currentOwner.newMethod(name, tree.pos, Flags.SYNTHETIC) setInfo ldef.symbol.info + val rhs1 = new TreeSymSubstituter(List(ldef.symbol), List(sym)).transform(rhs) + val rhsVal = transExpr(rhs1, None, getAnswerTypeAnn(tree.tpe)) changeOwner (currentOwner -> sym) val stm1 = localTyper.typed(DefDef(sym, rhsVal)) val expr = localTyper.typed(Apply(Ident(sym), List())) @@ -355,12 +351,12 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with val valueTpe = removeAllCPSAnnotations(expr.tpe) - val sym = currentOwner.newValue(tree.pos, newTermName(unit.fresh.newName("tmp"))) - .setInfo(valueTpe) - .setFlag(Flags.SYNTHETIC) - .setAnnotations(List(AnnotationInfo(MarkerCPSSym.tpe, Nil, Nil))) - - new ChangeOwnerTraverser(currentOwner, sym) traverse expr + val sym: Symbol = ( + currentOwner.newValue(newTermName(unit.fresh.newName("tmp")), tree.pos, Flags.SYNTHETIC) + setInfo valueTpe + setAnnotations List(AnnotationInfo(MarkerCPSSym.tpe, Nil, Nil)) + ) + expr.changeOwner(currentOwner -> sym) (stms ::: List(ValDef(sym, expr) setType(NoType)), Ident(sym) setType(valueTpe) setPos(tree.pos), linearize(spc, spcVal)(unit, tree.pos)) diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala index 960b27c52f..b2a1546b4e 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala @@ -192,18 +192,17 @@ abstract class SelectiveCPSTransform extends PluginComponent with // val expr2 = if (catches.nonEmpty) { val pos = catches.head.pos - val argSym = currentOwner.newValueParameter(pos, cpsNames.ex).setInfo(ThrowableClass.tpe) + val argSym = currentOwner.newValueParameter(cpsNames.ex, pos).setInfo(ThrowableClass.tpe) val rhs = Match(Ident(argSym), catches1) val fun = Function(List(ValDef(argSym)), rhs) - val funSym = currentOwner.newValueParameter(pos, cpsNames.catches).setInfo(appliedType(PartialFunctionClass.tpe, List(ThrowableClass.tpe, targettp))) + val funSym = currentOwner.newValueParameter(cpsNames.catches, pos).setInfo(appliedType(PartialFunctionClass.tpe, List(ThrowableClass.tpe, targettp))) val funDef = localTyper.typed(atPos(pos) { ValDef(funSym, fun) }) val expr2 = localTyper.typed(atPos(pos) { Apply(Select(expr1, expr1.tpe.member(cpsNames.flatMapCatch)), List(Ident(funSym))) }) argSym.owner = fun.symbol - val chown = new ChangeOwnerTraverser(currentOwner, fun.symbol) - chown.traverse(rhs) + rhs.changeOwner(currentOwner -> fun.symbol) - val exSym = currentOwner.newValueParameter(pos, cpsNames.ex).setInfo(ThrowableClass.tpe) + val exSym = currentOwner.newValueParameter(cpsNames.ex, pos).setInfo(ThrowableClass.tpe) val catch2 = { localTyper.typedCases(tree, List( CaseDef(Bind(exSym, Typed(Ident("_"), TypeTree(ThrowableClass.tpe))), Apply(Select(Ident(funSym), nme.isDefinedAt), List(Ident(exSym))), @@ -263,8 +262,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with val tpe = vd.symbol.tpe val rhs1 = atOwner(vd.symbol) { transform(rhs) } - - new ChangeOwnerTraverser(vd.symbol, currentOwner).traverse(rhs1) // TODO: don't traverse twice + rhs1.changeOwner(vd.symbol -> currentOwner) // TODO: don't traverse twice log("valdef symbol " + vd.symbol + " has type " + tpe) log("right hand side " + rhs1 + " has type " + rhs1.tpe) @@ -302,11 +300,11 @@ abstract class SelectiveCPSTransform extends PluginComponent with } def applyCombinatorFun(ctxR: Tree, body: Tree) = { - val arg = currentOwner.newValueParameter(ctxR.pos, name).setInfo(tpe) + val arg = currentOwner.newValueParameter(name, ctxR.pos).setInfo(tpe) val body1 = (new TreeSymSubstituter(List(vd.symbol), List(arg)))(body) val fun = localTyper.typed(atPos(vd.symbol.pos) { Function(List(ValDef(arg)), body1) }) // types body as well arg.owner = fun.symbol - new ChangeOwnerTraverser(currentOwner, fun.symbol).traverse(body1) + body1.changeOwner(currentOwner -> fun.symbol) // see note about multiple traversals above diff --git a/src/library/scala/Function1.scala b/src/library/scala/Function1.scala index dc8e67bbb0..7517e6604b 100644 --- a/src/library/scala/Function1.scala +++ b/src/library/scala/Function1.scala @@ -24,10 +24,18 @@ package scala * assert(succ(0) == anonfun1(0)) * } * }}} + * + * Note that `Function1` does not define a total function, as might + * be suggested by the existence of [[scala.PartialFunction]]. The only + * distinction between `Function1` and `PartialFunction` is that the + * latter can specify inputs which it will not handle. + * */ @annotation.implicitNotFound(msg = "No implicit view available from ${T1} => ${R}.") trait Function1[@specialized(scala.Int, scala.Long, scala.Float, scala.Double) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double) +R] extends AnyRef { self => - /** Apply the body of this function to the argument. + /** Apply the body of this function to the argument. It may throw an + * exception. + * * @return the result of function application. */ def apply(v1: T1): R diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala index b2910c2278..70caff0221 100644 --- a/src/library/scala/PartialFunction.scala +++ b/src/library/scala/PartialFunction.scala @@ -13,6 +13,36 @@ package scala * The function `isDefinedAt` allows to test dynamically if a value is in * the domain of the function. * + * Even if `isDefinedAt` returns true for an `a: A`, calling `apply(a)` may + * still throw an exception, so the following code is legal: + * + * {{{ + * val f: PartialFunction[Int, Any] = { case _ => 1/0 } + * }}} + * + * The main distinction between `PartialFunction` and [[scala.Function1]] is + * that the user of a `PartialFunction` may choose to do something different + * with input that is declared to be outside its domain. For example: + * + * {{{ + * val sample = 1 to 10 + * val isEven: PartialFunction[Int, String] = { + * case x if x % 2 == 0 => x+" is even" + * } + * + * // the method collect can use isDefinedAt to select which members to collect + * val evenNumbers = sample collect isEven + * + * val isOdd: PartialFunction[Int, String] = { + * case x if x % 2 == 1 => x+" is odd" + * } + * + * // the method orElse allows chaining another partial function to handle + * // input outside the declared domain + * val numbers = sample map (isEven orElse isOdd) + * }}} + * + * * @author Martin Odersky * @version 1.0, 16/07/2003 */ diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index b175fb9e1d..824e048e73 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -269,7 +269,7 @@ object Predef extends LowPriorityImplicits { def printf(text: String, xs: Any*) = Console.print(text.format(xs: _*)) def readLine(): String = Console.readLine() - def readLine(text: String, args: Any*) = Console.readLine(text, args) + def readLine(text: String, args: Any*) = Console.readLine(text, args: _*) def readBoolean() = Console.readBoolean() def readByte() = Console.readByte() def readShort() = Console.readShort() diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala new file mode 100644 index 0000000000..6116547aa2 --- /dev/null +++ b/src/library/scala/StringContext.scala @@ -0,0 +1,191 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +import collection.mutable.ArrayBuffer + +/** A class to support string interpolation. + * This class supports string interpolation as outlined in Scala SIP-11. + * It needs to be fully documented once the SIP is accepted. + * + * @param parts The parts that make up the interpolated string, + * without the expressions that get inserted by interpolation. + */ +case class StringContext(parts: String*) { + + import StringContext._ + + /** Checks that the given arguments `args` number one less than the number + * of `parts` supplied to the enclosing `StringContext`. + * @param `args` The arguments to be checked. + * @throws An `IllegalArgumentException` if this is not the case. + */ + def checkLengths(args: Any*): Unit = + if (parts.length != args.length + 1) + throw new IllegalArgumentException("wrong number of arguments for interpolated string") + + + /** The simple string interpolator. + * + * It inserts its arguments between corresponding parts of the string context. + * It also treats standard escape sequences as defined in the Scala specification. + * @param `args` The arguments to be inserted into the resulting string. + * @throws An `IllegalArgumentException` + * if the number of `parts` in the enclosing `StringContext` does not exceed + * the number of arguments `arg` by exactly 1. + * @throws A `StringContext.InvalidEscapeException` if if a `parts` string contains a backslash (`\`) character + * that does not start a valid escape sequence. + */ + def s(args: Any*) = { + checkLengths(args: _*) + val pi = parts.iterator + val ai = args.iterator + val bldr = new java.lang.StringBuilder(treatEscapes(pi.next)) + while (ai.hasNext) { + bldr append ai.next + bldr append treatEscapes(pi.next) + } + bldr.toString + } + + /** The formatted string interpolator. + * + * It inserts its arguments between corresponding parts of the string context. + * It also treats standard escape sequences as defined in the Scala specification. + * Finally, if an interpolated expression is followed by a `parts` string + * that starts with a formatting specifier, the expression is formatted according to that + * specifier. All specifiers allowed in Java format strings are handled, and in the same + * way they are treated in Java. + * + * @param `args` The arguments to be inserted into the resulting string. + * @throws An `IllegalArgumentException` + * if the number of `parts` in the enclosing `StringContext` does not exceed + * the number of arguments `arg` by exactly 1. + * @throws A `StringContext.InvalidEscapeException` if a `parts` string contains a backslash (`\`) character + * that does not start a valid escape sequence. + * + * Note: The `f` method works by assembling a format string from all the `parts` strings and using + * `java.lang.String.format` to format all arguments with that format string. The format string is + * obtained by concatenating all `parts` strings, and performing two transformations: + * + * 1. Let a _formatting position_ be a start of any `parts` string except the first one. + * If a formatting position does not refer to a `%` character (which is assumed to + * start a format specifier), then the string format specifier `%s` is inserted. + * + * 2. Any `%` characters not in formatting positions are left in the resulting + * string literally. This is achieved by replacing each such occurrence by a string + * format specifier `%s` and adding a corresponding argument string `"%"`. + */ + def f(args: Any*) = { + checkLengths(args: _*) + val pi = parts.iterator + val ai = args.iterator + val bldr = new java.lang.StringBuilder + val args1 = new ArrayBuffer[Any] + def copyString(first: Boolean): Unit = { + val str = treatEscapes(pi.next) + var start = 0 + var idx = 0 + if (!first) { + if ((str charAt 0) != '%') + bldr append "%s" + idx = 1 + } + val len = str.length + while (idx < len) { + if (str(idx) == '%') { + bldr append (str substring (start, idx)) append "%s" + args1 += "%" + start = idx + 1 + } + idx += 1 + } + bldr append (str substring (start, idx)) + } + copyString(first = true) + while (pi.hasNext) { + args1 += ai.next + copyString(first = false) + } + bldr.toString format (args1: _*) + } +} + +object StringContext { + + /** An exception that is thrown if a string contains a backslash (`\`) character that + * that does not start a valid escape sequence. + * @param str The offending string + * @param idx The index of the offending backslash character in `str`. + */ + class InvalidEscapeException(str: String, idx: Int) + extends IllegalArgumentException("invalid escape character at index "+idx+" in \""+str+"\"") + + /** Expands standard Scala escape sequences in a string. + * Escape sequences are: + * control: `\b`, `\t`, `\n`, `\f`, `\r` + * escape: `\\`, `\"`, `\'` + * octal: `\d` `\dd` `\ddd` where `d` is an octal digit between `0` and `7`. + * + * @param A string that may contain escape sequences + * @return The string with all escape sequences expanded. + */ + def treatEscapes(str: String): String = { + lazy val bldr = new java.lang.StringBuilder + val len = str.length + var start = 0 + var cur = 0 + var idx = 0 + def output(ch: Char) = { + bldr append str substring (start, cur) + bldr append ch + start = idx + } + while (idx < len) { + cur = idx + if (str(idx) == '\\') { + idx += 1 + if ('0' <= str(idx) && str(idx) <= '7') { + val leadch = str(idx) + var oct = leadch - '0' + idx += 1 + if ('0' <= str(idx) && str(idx) <= '7') { + oct = oct * 8 + str(idx) - '0' + idx += 1 + if (leadch <= '3' && '0' <= str(idx) && str(idx) <= '7') { + oct = oct * 8 + str(idx) - '0' + idx += 1 + } + } + output(oct.toChar) + } else { + val ch = str(idx) + idx += 1 + output { + ch match { + case 'b' => '\b' + case 't' => '\t' + case 'n' => '\n' + case 'f' => '\f' + case 'r' => '\r' + case '\"' => '\"' + case '\'' => '\'' + case '\\' => '\\' + case _ => throw new InvalidEscapeException(str, cur) + } + } + } + } else { + idx += 1 + } + } + if (start == 0) str + else (bldr append str.substring(start, idx)).toString + } +} diff --git a/src/library/scala/collection/GenTraversableLike.scala b/src/library/scala/collection/GenTraversableLike.scala index 122eec2d90..c837775cf9 100644 --- a/src/library/scala/collection/GenTraversableLike.scala +++ b/src/library/scala/collection/GenTraversableLike.scala @@ -177,7 +177,28 @@ trait GenTraversableLike[+A, +Repr] extends GenTraversableOnce[A] with Paralleli def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That /** Builds a new collection by applying a function to all elements of this $coll - * and concatenating the results. + * and using the elements of the resulting collections. For example: + * + * {{{ + * def getWords(lines: Seq[String]): Seq[String] = lines flatMap (line => line split "\\W+") + * }}} + * + * The type of the resulting collection is guided by the static type of $coll. This might + * cause unexpected results sometimes. For example: + * + * {{{ + * // lettersOf will return a Seq[Char] of likely repeated letters, instead of a Set + * def lettersOf(words: Seq[String]) = words flatMap (word => word.toSet) + * + * // lettersOf will return a Set[Char], not a Seq + * def lettersOf(words: Seq[String]) = words.toSet flatMap (word => word.toSeq) + * + * // xs will be a an Iterable[Int] + * val xs = Map("a" -> List(11,111), "b" -> List(22,222)).flatMap(_._2) + * + * // ys will be a Map[Int, Int] + * val ys = Map("a" -> List(1 -> 11,1 -> 111), "b" -> List(2 -> 22,2 -> 222)).flatMap(_._2) + * }}} * * @param f the function to apply to each element. * @tparam B the element type of the returned collection. diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 3e42e7812b..305f8d768d 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -471,7 +471,7 @@ trait GenTraversableOnce[+A] { * $willNotTerminateInf * @return an indexed sequence containing all elements of this $coll. */ - def toIndexedSeq[A1 >: A]: immutable.IndexedSeq[A1] + def toIndexedSeq: immutable.IndexedSeq[A] /** Converts this $coll to a stream. * $willNotTerminateInf diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index 94f7e9701b..d213e60112 100755 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -48,7 +48,8 @@ package scala.collection * @author Martin Odersky * @since 2.8.1 */ -object JavaConverters { + +trait JavaConverters { import java.{ lang => jl, util => ju } import java.util.{ concurrent => juc } import JavaConversions._ @@ -536,3 +537,5 @@ object JavaConverters { propertiesAsScalaMapConverter(p) } + +object JavaConverters extends JavaConverters
\ No newline at end of file diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index b6b4bfb96d..6d84b4276b 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -152,7 +152,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] with GenSeqLike[A, Repr] if (!hasNext) Iterator.empty.next - val result = (self.newBuilder ++= elms).result + val result = (self.newBuilder ++= elms.toList).result var i = idxs.length - 2 while(i >= 0 && idxs(i) >= idxs(i+1)) i -= 1 diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index e2acc0b3e0..36d45c0c8a 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -535,7 +535,7 @@ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] val b = newBuilder var go = false for (x <- this) { - if (!p(x)) go = true + if (!go && !p(x)) go = true if (go) b += x } b.result @@ -709,6 +709,9 @@ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] * outer $coll containing this `WithFilter` instance that satisfy * predicate `p` and concatenating the results. * + * The type of the resulting collection will be guided by the static type + * of the outer $coll. + * * @param f the function to apply to each element. * @tparam B the element type of the returned collection. * @tparam That $thatinfo diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala index 908c4c808d..5bb2e563f6 100644 --- a/src/library/scala/collection/TraversableOnce.scala +++ b/src/library/scala/collection/TraversableOnce.scala @@ -245,7 +245,7 @@ trait TraversableOnce[+A] extends GenTraversableOnce[A] { def toSeq: Seq[A] = toStream - def toIndexedSeq[B >: A]: immutable.IndexedSeq[B] = immutable.IndexedSeq() ++ seq + def toIndexedSeq: immutable.IndexedSeq[A] = immutable.IndexedSeq() ++ seq def toBuffer[B >: A]: mutable.Buffer[B] = new ArrayBuffer[B] ++= seq diff --git a/src/library/scala/collection/TraversableProxyLike.scala b/src/library/scala/collection/TraversableProxyLike.scala index 15565e57c6..e7e797391e 100644 --- a/src/library/scala/collection/TraversableProxyLike.scala +++ b/src/library/scala/collection/TraversableProxyLike.scala @@ -77,7 +77,7 @@ trait TraversableProxyLike[+A, +Repr <: TraversableLike[A, Repr] with Traversabl override def toList: List[A] = self.toList override def toIterable: Iterable[A] = self.toIterable override def toSeq: Seq[A] = self.toSeq - override def toIndexedSeq[B >: A] = self.toIndexedSeq + override def toIndexedSeq: immutable.IndexedSeq[A] = self.toIndexedSeq override def toBuffer[B >: A] = self.toBuffer override def toStream: Stream[A] = self.toStream override def toSet[B >: A]: immutable.Set[B] = self.toSet diff --git a/src/library/scala/collection/generic/GenericTraversableTemplate.scala b/src/library/scala/collection/generic/GenericTraversableTemplate.scala index 12c1a75c7a..7333074778 100644 --- a/src/library/scala/collection/generic/GenericTraversableTemplate.scala +++ b/src/library/scala/collection/generic/GenericTraversableTemplate.scala @@ -116,7 +116,19 @@ trait GenericTraversableTemplate[+A, +CC[X] <: GenTraversable[X]] extends HasNew } /** Converts this $coll of traversable collections into - * a $coll in which all element collections are concatenated. + * a $coll formed by the elements of these traversable + * collections. + * + * The resulting collection's type will be guided by the + * static type of $coll. For example: + * + * {{{ + * val xs = List(Set(1, 2, 3), Set(1, 2, 3)) + * // xs == List(1, 2, 3, 1, 2, 3) + * + * val ys = Set(List(1, 2, 3), List(3, 2, 1)) + * // ys == Set(1, 2, 3) + * }}} * * @tparam B the type of the elements of each traversable collection. * @param asTraversable an implicit conversion which asserts that the element diff --git a/src/library/scala/collection/generic/MutableSortedSetFactory.scala b/src/library/scala/collection/generic/MutableSortedSetFactory.scala new file mode 100644 index 0000000000..b235379575 --- /dev/null +++ b/src/library/scala/collection/generic/MutableSortedSetFactory.scala @@ -0,0 +1,33 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection +package generic + +import scala.collection.mutable.{ Builder, GrowingBuilder } + +/** + * @define Coll mutable.SortedSet + * @define coll mutable sorted + * + * @author Lucien Pereira + * + */ +abstract class MutableSortedSetFactory[CC[A] <: mutable.SortedSet[A] with SortedSetLike[A, CC[A]] with mutable.Set[A] with mutable.SetLike[A, CC[A]]] extends SortedSetFactory[CC] { + + /** + * mutable.SetBuilder uses '+' which is not a primitive for anything extending mutable.SetLike, + * this causes serious perfomances issues since each time 'elems = elems + x' + * is evaluated elems is cloned (which is O(n)). + * + * Fortunately GrowingBuilder comes to rescue. + * + */ + override def newBuilder[A](implicit ord: Ordering[A]): Builder[A, CC[A]] = new GrowingBuilder[A, CC[A]](empty) + +} diff --git a/src/library/scala/collection/generic/TraversableForwarder.scala b/src/library/scala/collection/generic/TraversableForwarder.scala index 6529fe4a79..3d723a1feb 100644 --- a/src/library/scala/collection/generic/TraversableForwarder.scala +++ b/src/library/scala/collection/generic/TraversableForwarder.scala @@ -61,7 +61,7 @@ trait TraversableForwarder[+A] extends Traversable[A] { override def toList: List[A] = underlying.toList override def toIterable: Iterable[A] = underlying.toIterable override def toSeq: Seq[A] = underlying.toSeq - override def toIndexedSeq[B >: A] = underlying.toIndexedSeq + override def toIndexedSeq = underlying.toIndexedSeq override def toBuffer[B >: A] = underlying.toBuffer override def toStream: Stream[A] = underlying.toStream override def toSet[B >: A]: immutable.Set[B] = underlying.toSet diff --git a/src/library/scala/collection/immutable/IndexedSeq.scala b/src/library/scala/collection/immutable/IndexedSeq.scala index bbbef158af..e3939001d8 100644 --- a/src/library/scala/collection/immutable/IndexedSeq.scala +++ b/src/library/scala/collection/immutable/IndexedSeq.scala @@ -22,7 +22,7 @@ trait IndexedSeq[+A] extends Seq[A] with GenericTraversableTemplate[A, IndexedSeq] with IndexedSeqLike[A, IndexedSeq[A]] { override def companion: GenericCompanion[IndexedSeq] = IndexedSeq - override def toIndexedSeq[B >: A]: IndexedSeq[B] = this + override def toIndexedSeq: IndexedSeq[A] = this override def seq: IndexedSeq[A] = this } diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index c6f056bd81..e9ecc75e0f 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -316,28 +316,7 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend override def tail : List[B] = tl override def isEmpty: Boolean = false - import java.io._ - private def writeObject(out: ObjectOutputStream) { - var xs: List[B] = this - while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail } - out.writeObject(ListSerializeEnd) - } - - private def readObject(in: ObjectInputStream) { - hd = in.readObject.asInstanceOf[B] - assert(hd != ListSerializeEnd) - var current: ::[B] = this - while (true) in.readObject match { - case ListSerializeEnd => - current.tl = Nil - return - case a : Any => - val list : ::[B] = new ::(a.asInstanceOf[B], Nil) - current.tl = list - current = list - } - } } /** $factoryInfo diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index c92c0268b6..7537558f0b 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -286,18 +286,36 @@ extends collection.AbstractSeq[Int] object Range { private[immutable] val MAX_PRINT = 512 // some arbitrary value - /** Counts in "Long arithmetic" so we can recognize overflow. + /** Counts the number of range elements. + * @pre step != 0 + * If the size of the range exceeds Int.MaxValue, the + * result will be negative. */ - def count(start: Int, end: Int, step: Int): Int = - count(start, end, step, false) - def count(start: Int, end: Int, step: Int, isInclusive: Boolean): Int = { - // faster path for the common counting range - if (start >= 0 && end > start && end < scala.Int.MaxValue && step == 1) - (end - start) + ( if (isInclusive) 1 else 0 ) - else - NumericRange.count[Long](start, end, step, isInclusive) + if (step == 0) + throw new IllegalArgumentException("step cannot be 0.") + + val isEmpty = ( + if (start == end) !isInclusive + else if (start < end) step < 0 + else step > 0 + ) + if (isEmpty) 0 + else { + // Counts with Longs so we can recognize too-large ranges. + val gap: Long = end.toLong - start.toLong + val jumps: Long = gap / step + // Whether the size of this range is one larger than the + // number of full-sized jumps. + val hasStub = isInclusive || (gap % step != 0) + val result: Long = jumps + ( if (hasStub) 1 else 0 ) + + if (result > scala.Int.MaxValue) -1 + else result.toInt + } } + def count(start: Int, end: Int, step: Int): Int = + count(start, end, step, false) class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) { // override def par = new ParRange(this) diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index e6587f9615..2eb2f8eb09 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -929,13 +929,19 @@ self => /** A specialized, extra-lazy implementation of a stream iterator, so it can * iterate as lazily as it traverses the tail. */ -final class StreamIterator[+A](self: Stream[A]) extends AbstractIterator[A] with Iterator[A] { +final class StreamIterator[+A] private() extends AbstractIterator[A] with Iterator[A] { + def this(self: Stream[A]) { + this() + these = new LazyCell(self) + } + // A call-by-need cell. class LazyCell(st: => Stream[A]) { lazy val v = st } - private var these = new LazyCell(self) + private var these: LazyCell = _ + def hasNext: Boolean = these.v.nonEmpty def next(): A = if (isEmpty) Iterator.empty.next diff --git a/src/library/scala/collection/interfaces/TraversableOnceMethods.scala b/src/library/scala/collection/interfaces/TraversableOnceMethods.scala index 5e1325fef6..471e977134 100644 --- a/src/library/scala/collection/interfaces/TraversableOnceMethods.scala +++ b/src/library/scala/collection/interfaces/TraversableOnceMethods.scala @@ -48,7 +48,7 @@ trait TraversableOnceMethods[+A] { // conversions def toArray[B >: A : ClassManifest]: Array[B] def toBuffer[B >: A]: mutable.Buffer[B] - def toIndexedSeq[B >: A]: immutable.IndexedSeq[B] + def toIndexedSeq: immutable.IndexedSeq[A] def toIterable: Iterable[A] def toIterator: Iterator[A] def toList: List[A] diff --git a/src/library/scala/collection/mutable/AVLTree.scala b/src/library/scala/collection/mutable/AVLTree.scala new file mode 100644 index 0000000000..0cf6cb06e5 --- /dev/null +++ b/src/library/scala/collection/mutable/AVLTree.scala @@ -0,0 +1,206 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection +package mutable + +import annotation.tailrec + +/** + * An immutable AVL Tree implementation used by mutable.TreeSet + * + * @author Lucien Pereira + * + */ +private[mutable] sealed trait AVLTree[+A] extends Serializable { + def balance: Int + + def depth: Int + +} + +private case class Node[A](val data: A, val left: AVLTree[A], val right: AVLTree[A]) extends AVLTree[A] { + override val balance: Int = right.depth - left.depth + + override val depth: Int = math.max(left.depth, right.depth) + 1 + +} + +private case object Leaf extends AVLTree[Nothing] { + override val balance: Int = 0 + + override val depth: Int = -1 + +} + +private[mutable] object AVLTree { + + /** + * Returns a new tree containing the given element. + * Thows an IllegalArgumentException if element is already present. + * + */ + def insert[A](value: A, tree: AVLTree[A], ordering: Ordering[A]): AVLTree[A] = { + @tailrec + def insertTC(value: A, tree: AVLTree[A], reassemble: AVLTree[A] => AVLTree[A]): AVLTree[A] = tree match { + case Leaf => reassemble(Node(value, Leaf, Leaf)) + + case Node(a, left, right) => if (0 == ordering.compare(value, a)) { + throw new IllegalArgumentException() + } else if (-1 == ordering.compare(value, a)) { + insertTC(value, left, x => reassemble(rebalance(Node(a, x, right)))) + } else { + insertTC(value, right, x => reassemble(rebalance(Node(a, left, x)))) + } + } + + insertTC(value, tree, x => rebalance(x)) + } + + def contains[A](value: A, tree: AVLTree[A], ordering: Ordering[A]): Boolean = tree match { + case Leaf => false + + case Node(a, left, right) => if (0 == ordering.compare(value, a)) { + true + } else if (-1 == ordering.compare(value, a)) { + contains(value, left, ordering) + } else { + contains(value, right, ordering) + } + } + + /** + * Return a new tree which not contains given element. + * + */ + def remove[A](value: A, tree: AVLTree[A], ordering: Ordering[A]): AVLTree[A] = tree match { + case Leaf => throw new NoSuchElementException() + + case Node(a, Leaf, Leaf) => if (0 == ordering.compare(value, a)) { + Leaf + } else { + throw new NoSuchElementException() + } + + case Node(a, left, right@Node(_, _, _)) => if (0 == ordering.compare(value, a)) { + val (min, newRight) = removeMin(right) + rebalance(Node(min, left, newRight)) + } else if (-1 == ordering.compare(value, a)) { + rebalance(Node(a, remove(value, left, ordering), right)) + } else { + rebalance(Node(a, left, remove(value, right, ordering))) + } + + case Node(a, left@Node(_, _, _), right) => if (0 == ordering.compare(value, a)) { + val (max, newLeft) = removeMax(left) + rebalance(Node(max, newLeft, right)) + } else if (-1 == ordering.compare(value, a)) { + rebalance(Node(a, remove(value, left, ordering), right)) + } else { + rebalance(Node(a, left, remove(value, right, ordering))) + } + } + + /** + * Return a tuple containing the biggest element of the provided tree + * and a new tree from which this element has been extracted. + * + */ + def removeMax[A](tree: Node[A]): (A, AVLTree[A]) = { + @tailrec + def removeMaxTC(tree: AVLTree[A], assemble: (A, AVLTree[A]) => (A, AVLTree[A])): (A, AVLTree[A]) = tree match { + case Node(a, Leaf, Leaf) => assemble(a, Leaf) + case Node(a, left, Leaf) => assemble(a, left) + case Node(a, left, right) => removeMaxTC(right, + (max: A, avl: AVLTree[A]) => assemble(max, rebalance(Node(a, left, avl)))) + case Leaf => sys.error("Should not happen.") + } + + removeMaxTC(tree, (a, b) => (a, b)) + } + + /** + * Return a tuple containing the smallest element of the provided tree + * and a new tree from which this element has been extracted. + * + */ + def removeMin[A](tree: Node[A]): (A, AVLTree[A]) = { + @tailrec + def removeMinTC(tree: AVLTree[A], assemble: (A, AVLTree[A]) => (A, AVLTree[A])): (A, AVLTree[A]) = tree match { + case Node(a, Leaf, Leaf) => assemble(a, Leaf) + case Node(a, Leaf, right) => assemble(a, right) + case Node(a, left, right) => removeMinTC(left, + (min: A, avl: AVLTree[A]) => assemble(min, rebalance(Node(a, avl, right)))) + case Leaf => sys.error("Should not happen.") + } + + removeMinTC(tree, (a, b) => (a, b)) + } + + /** + * Returns a bounded stream of elements in the tree. + * + */ + def toStream[A](tree: AVLTree[A], isLeftAcceptable: A => Boolean, isRightAcceptable: A => Boolean): Stream[A] = tree match { + case Leaf => Stream.empty + + case Node(a, left, right) => if (isLeftAcceptable(a)) { + if (isRightAcceptable(a)) { + toStream(left, isLeftAcceptable, isRightAcceptable) ++ Stream(a) ++ toStream(right, isLeftAcceptable, isRightAcceptable) + } else { + toStream(left, isLeftAcceptable, isRightAcceptable) + } + } else if (isRightAcceptable(a)) { + toStream(right, isLeftAcceptable, isRightAcceptable) + } else { + Stream.empty + } + } + + /** + * Returns a bounded iterator of elements in the tree. + * + */ + def iterator[A](tree: AVLTree[A], isLeftAcceptable: A => Boolean, isRightAcceptable: A => Boolean): Iterator[A] = + toStream(tree, isLeftAcceptable, isRightAcceptable).iterator + + def rebalance[A](tree: AVLTree[A]): AVLTree[A] = (tree, tree.balance) match { + case (node@Node(_, left, _), -2) => left.balance match { + case 1 => doubleRightRotation(node) + case _ => rightRotation(node) + } + + case (node@Node(_, _, right), 2) => right.balance match { + case -1 => doubleLeftRotation(node) + case _ => leftRotation(node) + } + + case _ => tree + } + + def leftRotation[A](tree: Node[A]): AVLTree[A] = tree.right match { + case Node(b, left, right) => Node(b, Node(tree.data, tree.left, left), right) + case _ => sys.error("Should not happen.") + } + + def rightRotation[A](tree: Node[A]): AVLTree[A] = tree.left match { + case Node(b, left, right) => Node(b, left, Node(tree.data, right, tree.right)) + case _ => sys.error("Should not happen.") + } + + def doubleLeftRotation[A](tree: Node[A]): AVLTree[A] = tree.right match { + case right@Node(b, l, r) => leftRotation(Node(tree.data, tree.left, rightRotation(right))) + case _ => sys.error("Should not happen.") + } + + def doubleRightRotation[A](tree: Node[A]): AVLTree[A] = tree.left match { + case left@Node(b, l, r) => rightRotation(Node(tree.data, leftRotation(left), tree.right)) + case _ => sys.error("Should not happen.") + } + +} diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala index 131cdd0005..eb871135df 100644 --- a/src/library/scala/collection/mutable/ListBuffer.scala +++ b/src/library/scala/collection/mutable/ListBuffer.scala @@ -13,6 +13,7 @@ package mutable import generic._ import immutable.{List, Nil, ::} +import java.io._ /** A `Buffer` implementation back up by a list. It provides constant time * prepend and append. Most other operations are linear. @@ -53,6 +54,7 @@ final class ListBuffer[A] override def companion: GenericCompanion[ListBuffer] = ListBuffer import scala.collection.Traversable + import scala.collection.immutable.ListSerializeEnd private var start: List[A] = Nil private var last0: ::[A] = _ @@ -60,7 +62,49 @@ final class ListBuffer[A] private var len = 0 protected def underlying: immutable.Seq[A] = start - + + private def writeObject(out: ObjectOutputStream) { + // write start + var xs: List[A] = start + while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail } + out.writeObject(ListSerializeEnd) + + // no need to write last0 + + // write if exported + out.writeBoolean(exported) + + // write the length + out.writeInt(len) + } + + private def readObject(in: ObjectInputStream) { + // read start, set last0 appropriately + var elem: A = in.readObject.asInstanceOf[A] + if (elem == ListSerializeEnd) { + start = Nil + last0 = null + } else { + var current = new ::(elem, Nil) + start = current + elem = in.readObject.asInstanceOf[A] + while (elem != ListSerializeEnd) { + val list = new ::(elem, Nil) + current.tl = list + current = list + elem = in.readObject.asInstanceOf[A] + } + last0 = current + start + } + + // read if exported + exported = in.readBoolean() + + // read the length + len = in.readInt() + } + /** The current length of the buffer. * * This operation takes constant time. diff --git a/src/library/scala/collection/mutable/SortedSet.scala b/src/library/scala/collection/mutable/SortedSet.scala new file mode 100644 index 0000000000..d87fc0b4a2 --- /dev/null +++ b/src/library/scala/collection/mutable/SortedSet.scala @@ -0,0 +1,49 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection +package mutable + +import generic._ + +/** + * Base trait for mutable sorted set. + * + * @define Coll mutable.SortedSet + * @define coll mutable sorted set + * + * @author Lucien Pereira + * + */ +trait SortedSet[A] extends collection.SortedSet[A] with collection.SortedSetLike[A,SortedSet[A]] + with mutable.Set[A] with mutable.SetLike[A, SortedSet[A]] { + + /** Needs to be overridden in subclasses. */ + override def empty: SortedSet[A] = SortedSet.empty[A] + +} + +/** + * A template for mutable sorted set companion objects. + * + * @define Coll mutable.SortedSet + * @define coll mutable sorted set + * @define factoryInfo + * This object provides a set of operations needed to create sorted sets of type mutable.SortedSet. + * @define sortedSetCanBuildFromInfo + * Standard `CanBuildFrom` instance for sorted sets. + * + * @author Lucien Pereira + * + */ +object SortedSet extends MutableSortedSetFactory[SortedSet] { + implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = new SortedSetCanBuildFrom[A] + + def empty[A](implicit ord: Ordering[A]): SortedSet[A] = TreeSet.empty[A] + +} diff --git a/src/library/scala/collection/mutable/TreeSet.scala b/src/library/scala/collection/mutable/TreeSet.scala new file mode 100644 index 0000000000..38fa0c953f --- /dev/null +++ b/src/library/scala/collection/mutable/TreeSet.scala @@ -0,0 +1,123 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection +package mutable + +import generic._ + +/** + * @define Coll mutable.TreeSet + * @define coll mutable tree set + * @factoryInfo + * Companion object of TreeSet providing factory related utilities. + * + * @author Lucien Pereira + * + */ +object TreeSet extends MutableSortedSetFactory[TreeSet] { + /** + * The empty set of this type + */ + def empty[A](implicit ordering: Ordering[A]) = new TreeSet[A]() + +} + +/** + * A mutable SortedSet using an immutable AVL Tree as underlying data structure. + * + * @author Lucien Pereira + * + */ +class TreeSet[A](implicit val ordering: Ordering[A]) extends SortedSet[A] with SetLike[A, TreeSet[A]] + with SortedSetLike[A, TreeSet[A]] with Set[A] with Serializable { + + // Projection constructor + private def this(base: Option[TreeSet[A]], from: Option[A], until: Option[A])(implicit ordering: Ordering[A]) { + this(); + this.base = base + this.from = from + this.until = until + } + + private var base: Option[TreeSet[A]] = None + + private var from: Option[A] = None + + private var until: Option[A] = None + + private var avl: AVLTree[A] = Leaf + + private var cardinality: Int = 0 + + def resolve: TreeSet[A] = base.getOrElse(this) + + private def isLeftAcceptable(from: Option[A], ordering: Ordering[A])(a: A): Boolean = + from.map(x => ordering.gteq(a, x)).getOrElse(true) + + private def isRightAcceptable(until: Option[A], ordering: Ordering[A])(a: A): Boolean = + until.map(x => ordering.lt(a, x)).getOrElse(true) + + /** + * Cardinality store the set size, unfortunately a + * set view (given by rangeImpl) + * cannot take advantage of this optimisation + * + */ + override def size: Int = base.map(_ => super.size).getOrElse(cardinality) + + override def stringPrefix = "TreeSet" + + override def empty: TreeSet[A] = TreeSet.empty + + override def rangeImpl(from: Option[A], until: Option[A]): TreeSet[A] = new TreeSet(Some(this), from, until) + + override def -=(elem: A): this.type = { + try { + resolve.avl = AVLTree.remove(elem, resolve.avl, ordering) + resolve.cardinality = resolve.cardinality - 1 + } catch { + case e: NoSuchElementException => () + } + this + } + + override def +=(elem: A): this.type = { + try { + resolve.avl = AVLTree.insert(elem, resolve.avl, ordering) + resolve.cardinality = resolve.cardinality + 1 + } catch { + case e: IllegalArgumentException => () + } + this + } + + /** + * Thanks to the nature immutable of the + * underlying AVL Tree, we can share it with + * the clone. So clone complexity in time is O(1). + * + */ + override def clone: TreeSet[A] = { + val clone = new TreeSet[A](base, from, until) + clone.avl = resolve.avl + clone.cardinality = resolve.cardinality + clone + } + + override def contains(elem: A): Boolean = { + isLeftAcceptable(from, ordering)(elem) && + isRightAcceptable(until, ordering)(elem) && + AVLTree.contains(elem, resolve.avl, ordering) + } + + override def iterator: Iterator[A] = + AVLTree.iterator(resolve.avl, + isLeftAcceptable(from, ordering), + isRightAcceptable(until, ordering)) +} diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index f0d79ada9d..90b64c17f9 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -801,7 +801,7 @@ self: ParIterableLike[T, Repr, Sequential] => override def toList: List[T] = seq.toList - override def toIndexedSeq[U >: T]: collection.immutable.IndexedSeq[U] = seq.toIndexedSeq[U] + override def toIndexedSeq: collection.immutable.IndexedSeq[T] = seq.toIndexedSeq override def toStream: Stream[T] = seq.toStream diff --git a/src/library/scala/io/Codec.scala b/src/library/scala/io/Codec.scala index 1a27df1c10..d9cef0edb1 100644 --- a/src/library/scala/io/Codec.scala +++ b/src/library/scala/io/Codec.scala @@ -38,6 +38,9 @@ class Codec(val charSet: Charset) { private[this] var _decodingReplacement: String = null private[this] var _onCodingException: Handler = e => throw e + /** The name of the Codec. */ + override def toString = name + // these methods can be chained to configure the variables above def onMalformedInput(newAction: Action): this.type = { _onMalformedInput = newAction ; this } def onUnmappableCharacter(newAction: Action): this.type = { _onUnmappableCharacter = newAction ; this } diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index be08409636..8bd45c0e33 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -60,7 +60,7 @@ trait Manifest[T] extends ClassManifest[T] with Equals { override def hashCode = this.erasure.## } -sealed abstract class AnyValManifest[T <: AnyVal](override val toString: String) extends Manifest[T] with Equals { +abstract class AnyValManifest[T <: AnyVal](override val toString: String) extends Manifest[T] with Equals { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Manifest.Any) || (that eq Manifest.AnyVal) override def canEqual(other: Any) = other match { diff --git a/src/library/scala/reflect/ReflectionUtils.scala b/src/library/scala/reflect/ReflectionUtils.scala index b63a8645de..dfadfb4976 100644 --- a/src/library/scala/reflect/ReflectionUtils.scala +++ b/src/library/scala/reflect/ReflectionUtils.scala @@ -27,11 +27,15 @@ object ReflectionUtils { case ex if pf isDefinedAt unwrapThrowable(ex) => pf(unwrapThrowable(ex)) } - // Retrieves the MODULE$ field for the given class name. - def singletonInstance(className: String, cl: ClassLoader = getClass.getClassLoader): Option[AnyRef] = { + def singletonInstance(className: String, cl: ClassLoader = getClass.getClassLoader): AnyRef = { val name = if (className endsWith "$") className else className + "$" + val clazz = java.lang.Class.forName(name, true, cl) + val singleton = clazz getField "MODULE$" get null + singleton + } - try Some(java.lang.Class.forName(name, true, cl) getField "MODULE$" get null) + // Retrieves the MODULE$ field for the given class name. + def singletonInstanceOpt(className: String, cl: ClassLoader = getClass.getClassLoader): Option[AnyRef] = + try Some(singletonInstance(className, cl)) catch { case _: ClassNotFoundException => None } - } } diff --git a/src/library/scala/reflect/api/Mirror.scala b/src/library/scala/reflect/api/Mirror.scala index 53ac84f8cb..136f52b05f 100644 --- a/src/library/scala/reflect/api/Mirror.scala +++ b/src/library/scala/reflect/api/Mirror.scala @@ -13,7 +13,11 @@ trait Mirror extends Universe with RuntimeTypes with TreeBuildUtil { * to do: throws anything else? */ def classWithName(name: String): Symbol - + + /** Return a reference to the companion object of this class symbol + */ + def getCompanionObject(clazz: Symbol): AnyRef + /** The Scala class symbol corresponding to the runtime class of given object * @param The object from which the class is returned * @throws ? diff --git a/src/library/scala/reflect/api/Symbols.scala b/src/library/scala/reflect/api/Symbols.scala index 31bcdebe7e..8b4b170847 100755 --- a/src/library/scala/reflect/api/Symbols.scala +++ b/src/library/scala/reflect/api/Symbols.scala @@ -150,10 +150,10 @@ trait Symbols { self: Universe => */ def asTypeIn(site: Type): Type - /** A fresh symbol with given position `pos` and name `name` that has + /** A fresh symbol with given name `name`, position `pos` and flags `flags` that has * the current symbol as its owner. */ - def newNestedSymbol(pos: Position, name: Name): Symbol // needed by LiftCode + def newNestedSymbol(name: Name, pos: Position, flags: Long): Symbol // needed by LiftCode /** Low-level operation to set the symbol's flags * @return the symbol itself diff --git a/src/library/scala/reflect/api/TreePrinters.scala b/src/library/scala/reflect/api/TreePrinters.scala index 15fba0e418..88ef450ed9 100644 --- a/src/library/scala/reflect/api/TreePrinters.scala +++ b/src/library/scala/reflect/api/TreePrinters.scala @@ -28,7 +28,21 @@ trait TreePrinters { self: Universe => */ def newTreePrinter(out: PrintWriter): TreePrinter + // emits more or less verbatim representation of the provided tree + // todo. when LiftCode becomes a macro, throw this code away and use that macro class RawTreePrinter(out: PrintWriter) extends TreePrinter { + import scala.reflect.api.Modifier + import scala.reflect.api.Modifier._ + + def copypasteModifier(mod: Modifier.Value): String = mod match { + case mod @ ( + `protected` | `private` | `override` | + `abstract` | `final` | `sealed` | + `implicit` | `lazy` | `macro` | + `case` | `trait`) => "`" + mod.toString + "`" + case mod => mod.toString + } + def print(args: Any*): Unit = args foreach { case EmptyTree => print("EmptyTree") @@ -48,10 +62,35 @@ trait TreePrinters { self: Universe => case arg => print(arg) } - print(if (it.hasNext) ", " else ")") + print(if (it.hasNext) ", " else "") } + print(")") if (typesPrinted) print(".setType(", tree.tpe, ")") + case list: List[_] => + print("List(") + val it = list.iterator + while (it.hasNext) { + print(it.next()) + print(if (it.hasNext) ", " else "") + } + print(")") + case mods: Modifiers => + val parts = collection.mutable.ListBuffer[String]() + parts += "Set(" + mods.allModifiers.map{copypasteModifier}.mkString(", ") + ")" + parts += "newTypeName(\"" + mods.privateWithin.toString + "\")" + parts += "List(" + mods.annotations.map{showRaw}.mkString(", ") + ")" + + var keep = 3 + if (keep == 3 && mods.annotations.isEmpty) keep -= 1 + if (keep == 2 && mods.privateWithin == EmptyTypeName) keep -= 1 + if (keep == 1 && mods.allModifiers.isEmpty) keep -= 1 + + print("Modifiers(", parts.take(keep).mkString(", "), ")") + case name: Name => + if (name.isTermName) print("newTermName(\"") else print("newTypeName(\"") + print(name.toString) + print("\")") case arg => out.print(arg) } diff --git a/src/library/scala/reflect/api/MacroContext.scala b/src/library/scala/reflect/macro/Context.scala index e23357d26e..d0a2787fdf 100644 --- a/src/library/scala/reflect/api/MacroContext.scala +++ b/src/library/scala/reflect/macro/Context.scala @@ -1,7 +1,7 @@ package scala.reflect -package api +package macro -trait MacroContext extends Universe { +trait Context extends api.Universe { /** Mark a variable as captured; i.e. force boxing in a *Ref type. */ @@ -12,4 +12,4 @@ trait MacroContext extends Universe { */ def referenceCapturedVariable(id: Ident): Tree -}
\ No newline at end of file +} diff --git a/src/library/scala/reflect/package.scala b/src/library/scala/reflect/package.scala index 62592baa27..1c3e618520 100644 --- a/src/library/scala/reflect/package.scala +++ b/src/library/scala/reflect/package.scala @@ -8,7 +8,7 @@ package object reflect { // initialization, but in response to a doomed attempt to utilize it. lazy val mirror: api.Mirror = { // we use (Java) reflection here so that we can keep reflect.runtime and reflect.internals in a seperate jar - ReflectionUtils.singletonInstance("scala.reflect.runtime.Mirror") collect { case x: api.Mirror => x } getOrElse { + ReflectionUtils.singletonInstanceOpt("scala.reflect.runtime.Mirror") collect { case x: api.Mirror => x } getOrElse { throw new UnsupportedOperationException("Scala reflection not available on this platform") } } diff --git a/src/library/scala/xml/include/sax/Main.scala b/src/library/scala/xml/include/sax/Main.scala index 6b6f6c1593..f58097bcb9 100644 --- a/src/library/scala/xml/include/sax/Main.scala +++ b/src/library/scala/xml/include/sax/Main.scala @@ -10,11 +10,11 @@ package scala.xml package include.sax -import scala.xml.include._ import scala.util.control.Exception.{ catching, ignoring } import org.xml.sax.XMLReader import org.xml.sax.helpers.XMLReaderFactory +@deprecated("Code example will be moved to documentation.", "2.10.0") object Main { private val namespacePrefixes = "http://xml.org/sax/features/namespace-prefixes" private val lexicalHandler = "http://xml.org/sax/properties/lexical-handler" diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala index a08100a33f..a90a61a9aa 100644 --- a/src/partest/scala/tools/partest/PartestTask.scala +++ b/src/partest/scala/tools/partest/PartestTask.scala @@ -281,6 +281,26 @@ class PartestTask extends Task with CompilationPathProperty { } } getOrElse sys.error("Provided classpath does not contain a Scala library.") + val scalaCompiler = { + (classpath.list map { fs => new File(fs) }) find { f => + f.getName match { + case "scala-compiler.jar" => true + case "compiler" if (f.getParentFile.getName == "classes") => true + case _ => false + } + } + } getOrElse sys.error("Provided classpath does not contain a Scala compiler.") + + val scalaPartest = { + (classpath.list map { fs => new File(fs) }) find { f => + f.getName match { + case "scala-partest.jar" => true + case "partest" if (f.getParentFile.getName == "classes") => true + case _ => false + } + } + } getOrElse sys.error("Provided classpath does not contain a Scala partest.") + def scalacArgsFlat: Option[Seq[String]] = scalacArgs map (_ flatMap { a => val parts = a.getParts if(parts eq null) Seq[String]() else parts.toSeq @@ -294,6 +314,8 @@ class PartestTask extends Task with CompilationPathProperty { antFileManager.failed = runFailed antFileManager.CLASSPATH = ClassPath.join(classpath.list: _*) antFileManager.LATEST_LIB = scalaLibrary.getAbsolutePath + antFileManager.LATEST_COMP = scalaCompiler.getAbsolutePath + antFileManager.LATEST_PARTEST = scalaPartest.getAbsolutePath javacmd foreach (x => antFileManager.JAVACMD = x.getAbsolutePath) javaccmd foreach (x => antFileManager.JAVAC_CMD = x.getAbsolutePath) @@ -361,18 +383,18 @@ class PartestTask extends Task with CompilationPathProperty { private def oneResult(res: (String, Int)) = <testcase name={res._1}>{ - res._2 match { - case 0 => scala.xml.NodeSeq.Empty + res._2 match { + case 0 => scala.xml.NodeSeq.Empty case 1 => <failure message="Test failed"/> case 2 => <failure message="Test timed out"/> - } - }</testcase> + } + }</testcase> private def testReport(kind: String, results: Iterable[(String, Int)], succs: Int, fails: Int) = <testsuite name={kind} tests={(succs + fails).toString} failures={fails.toString}> - <properties/> - { - results.map(oneResult(_)) - } + <properties/> + { + results.map(oneResult(_)) + } </testsuite> } diff --git a/src/partest/scala/tools/partest/nest/AntRunner.scala b/src/partest/scala/tools/partest/nest/AntRunner.scala index 002e454b7b..4795e5551a 100644 --- a/src/partest/scala/tools/partest/nest/AntRunner.scala +++ b/src/partest/scala/tools/partest/nest/AntRunner.scala @@ -20,6 +20,8 @@ class AntRunner extends DirectRunner { var JAVAC_CMD: String = "javac" var CLASSPATH: String = _ var LATEST_LIB: String = _ + var LATEST_COMP: String = _ + var LATEST_PARTEST: String = _ val testRootPath: String = "test" val testRootDir: Directory = Directory(testRootPath) } diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala index 68688ff949..aea6bcc03a 100644 --- a/src/partest/scala/tools/partest/nest/CompileManager.scala +++ b/src/partest/scala/tools/partest/nest/CompileManager.scala @@ -111,6 +111,7 @@ class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler { try { NestUI.verbose("compiling "+toCompile) + NestUI.verbose("with classpath: "+global.classPath.toString) try new global.Run compile toCompile catch { case FatalError(msg) => diff --git a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala index b9b371d6cb..3d72227b04 100644 --- a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala +++ b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala @@ -157,9 +157,13 @@ class ConsoleFileManager extends FileManager { } LATEST_LIB = latestLibFile.getAbsolutePath + LATEST_COMP = latestCompFile.getAbsolutePath + LATEST_PARTEST = latestPartestFile.getAbsolutePath } var LATEST_LIB: String = "" + var LATEST_COMP: String = "" + var LATEST_PARTEST: String = "" var latestFile: File = _ var latestLibFile: File = _ diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala index 78184664c2..d3d50ca58c 100644 --- a/src/partest/scala/tools/partest/nest/DirectRunner.scala +++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala @@ -52,8 +52,15 @@ trait DirectRunner { val kindFiles = onlyValidTestPaths(_kindFiles) val groupSize = (kindFiles.length / numActors) + 1 - val consFM = new ConsoleFileManager - import consFM.{ latestCompFile, latestLibFile, latestPartestFile } + // @partest maintainer: we cannot create a fresh file manager here + // since the FM must respect --buildpath and --classpath from the command line + // for example, see how it's done in ReflectiveRunner + //val consFM = new ConsoleFileManager + //import consFM.{ latestCompFile, latestLibFile, latestPartestFile } + val latestCompFile = new File(fileManager.LATEST_COMP); + val latestLibFile = new File(fileManager.LATEST_LIB); + val latestPartestFile = new File(fileManager.LATEST_PARTEST); + val scalacheckURL = PathSettings.scalaCheck.toURL val scalaCheckParentClassLoader = ScalaClassLoader.fromURLs( List(scalacheckURL, latestCompFile.toURI.toURL, latestLibFile.toURI.toURL, latestPartestFile.toURI.toURL) diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala index 780f7a35e5..a4a94fe93e 100644 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ b/src/partest/scala/tools/partest/nest/FileManager.scala @@ -60,6 +60,8 @@ trait FileManager extends FileUtil { var CLASSPATH: String var LATEST_LIB: String + var LATEST_COMP: String + var LATEST_PARTEST: String var showDiff = false var updateCheck = false diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala index f6353faa6f..04f36ffa11 100644 --- a/src/partest/scala/tools/partest/nest/PathSettings.scala +++ b/src/partest/scala/tools/partest/nest/PathSettings.scala @@ -16,6 +16,9 @@ object PathSettings { private def cwd = Directory.Current getOrElse sys.error("user.dir property not set") private def isPartestDir(d: Directory) = (d.name == "test") && (d / srcDirName isDirectory) + private def findJar(d: Directory, name: String): Option[File] = findJar(d.files, name) + private def findJar(files: Iterator[File], name: String): Option[File] = + files filter (_ hasExtension "jar") find { _.name startsWith name } // Directory <root>/test lazy val testRoot: Directory = testRootDir getOrElse { @@ -33,7 +36,7 @@ object PathSettings { // Directory <root>/test/files/speclib lazy val srcSpecLibDir = Directory(srcDir / "speclib") - lazy val srcSpecLib: File = srcSpecLibDir.files find (_.name startsWith "instrumented") getOrElse { + lazy val srcSpecLib: File = findJar(srcSpecLibDir, "instrumented") getOrElse { sys.error("No instrumented.jar found in %s".format(srcSpecLibDir)) } @@ -51,7 +54,7 @@ object PathSettings { lazy val buildPackLibDir = Directory(buildDir / "pack" / "lib") lazy val scalaCheck: File = - buildPackLibDir.files ++ srcLibDir.files find (_.name startsWith "scalacheck") getOrElse { + findJar(buildPackLibDir.files ++ srcLibDir.files, "scalacheck") getOrElse { sys.error("No scalacheck jar found in '%s' or '%s'".format(buildPackLibDir, srcLibDir)) } } diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala index f39debf31d..7c6dd0848f 100644 --- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala +++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala @@ -58,10 +58,17 @@ class ReflectiveRunner { if (isPartestDebug) println("Loading classes from:\n" + sepUrls.mkString("\n")) - val paths = classPath match { - case Some(cp) => Nil - case _ => files.toList map (_.path) - } + // @partest maintainer: it seems to me that commented lines are incorrect + // if classPath is not empty, then it has been provided by the --classpath option + // which points to the root of Scala home (see ConsoleFileManager's testClasses and the true flag in the ctor for more information) + // this doesn't mean that we had custom Java classpath set, so we don't have to override latestXXXFiles from the file manager + // + //val paths = classPath match { + // case Some(cp) => Nil + // case _ => files.toList map (_.path) + //} + val paths = files.toList map (_.path) + val newClasspath = ClassPath.join(paths: _*) setProp("java.class.path", newClasspath) diff --git a/src/partest/scala/tools/partest/nest/SBTRunner.scala b/src/partest/scala/tools/partest/nest/SBTRunner.scala index ae54e51761..4c6f417df5 100644 --- a/src/partest/scala/tools/partest/nest/SBTRunner.scala +++ b/src/partest/scala/tools/partest/nest/SBTRunner.scala @@ -7,16 +7,18 @@ import scala.util.Properties.setProp object SBTRunner extends DirectRunner { - + val fileManager = new FileManager { var JAVACMD: String = "java" var JAVAC_CMD: String = "javac" var CLASSPATH: String = _ var LATEST_LIB: String = _ + var LATEST_COMP: String = _ + var LATEST_PARTEST: String = _ val testRootPath: String = "test" val testRootDir: Directory = Directory(testRootPath) } - + def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String):java.util.HashMap[String,Int] = { def convert(scalaM:scala.collection.immutable.Map[String,Int]):java.util.HashMap[String,Int] = { val javaM = new java.util.HashMap[String,Int]() @@ -25,9 +27,9 @@ object SBTRunner extends DirectRunner { } def failedOnlyIfRequired(files:List[File]):List[File]={ - if (fileManager.failed) files filter (x => fileManager.logFileExists(x, kind)) else files + if (fileManager.failed) files filter (x => fileManager.logFileExists(x, kind)) else files } - convert(runTestsForFiles(failedOnlyIfRequired(kindFiles.toList), kind)) + convert(runTestsForFiles(failedOnlyIfRequired(kindFiles.toList), kind)) } case class CommandLineOptions(classpath: Option[String] = None, @@ -38,7 +40,7 @@ object SBTRunner extends DirectRunner { def mainReflect(args: Array[String]): java.util.Map[String,Int] = { setProp("partest.debug", "true") setProperties() - + val Argument = new scala.util.matching.Regex("-(.*)") def parseArgs(args: Seq[String], data: CommandLineOptions): CommandLineOptions = args match { case Seq("--failed", rest @ _*) => parseArgs(rest, data.copy(justFailedTests = true)) @@ -50,10 +52,14 @@ object SBTRunner extends DirectRunner { } val config = parseArgs(args, CommandLineOptions()) fileManager.SCALAC_OPTS = config.scalacOptions - fileManager.CLASSPATH = config.classpath getOrElse error("No classpath set") + fileManager.CLASSPATH = config.classpath getOrElse sys.error("No classpath set") // Find scala library jar file... val lib: Option[String] = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches ".*scala-library.*\\.jar")).headOption - fileManager.LATEST_LIB = lib getOrElse error("No scala-library found! Classpath = " + fileManager.CLASSPATH) + fileManager.LATEST_LIB = lib getOrElse sys.error("No scala-library found! Classpath = " + fileManager.CLASSPATH) + val comp: Option[String] = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches ".*scala-compiler.*\\.jar")).headOption + fileManager.LATEST_COMP = comp getOrElse sys.error("No scala-compiler found! Classpath = " + fileManager.CLASSPATH) + val partest: Option[String] = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches ".*scala-partest.*\\.jar")).headOption + fileManager.LATEST_PARTEST = partest getOrElse sys.error("No scala-partest found! Classpath = " + fileManager.CLASSPATH) // TODO - Do something useful here!!! fileManager.JAVAC_CMD = "javac" fileManager.failed = config.justFailedTests @@ -63,7 +69,7 @@ object SBTRunner extends DirectRunner { val runs = config.tests.filterNot(_._2.isEmpty) // This next bit uses java maps... import collection.JavaConverters._ - (for { + (for { (testType, files) <- runs (path, result) <- reflectiveRunTestsForFiles(files,testType).asScala } yield (path, result)).seq asJava @@ -71,14 +77,12 @@ object SBTRunner extends DirectRunner { def main(args: Array[String]): Unit = { import collection.JavaConverters._ - val failures = for { - (path, result) <- mainReflect(args).asScala - if result == 1 || result == 2 - val resultName = (if(result == 1) " [FAILED]" else " [TIMEOUT]") - } yield path + resultName + val failures = ( + for ((path, result) <- mainReflect(args).asScala ; if result == 1 || result == 2) yield + path + ( if (result == 1) " [FAILED]" else " [TIMEOUT]" ) + ) // Re-list all failures so we can go figure out what went wrong. failures foreach System.err.println if(!failures.isEmpty) sys.exit(1) } } - diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala index 9c61097cb0..3e5fe35f9e 100644 --- a/src/partest/scala/tools/partest/nest/TestFile.scala +++ b/src/partest/scala/tools/partest/nest/TestFile.scala @@ -12,6 +12,7 @@ import java.io.{ File => JFile } import scala.tools.nsc.Settings import scala.tools.nsc.util.ClassPath import scala.tools.nsc.io._ +import scala.util.Properties.{ propIsSet, propOrElse, setProp } trait TestFileCommon { def file: JFile @@ -61,6 +62,10 @@ case class SpecializedTestFile(file: JFile, fileManager: FileManager) extends Te super.defineSettings(settings, setOutDir) && { // add the instrumented library version to classpath settings.classpath prepend PathSettings.srcSpecLib.toString + // @partest maintainer: if we use a custom Scala build (specified via --classpath) + // then the classes provided by it will come earlier than instrumented.jar in the resulting classpath + // this entire classpath business needs a thorough solution + if (propIsSet("java.class.path")) setProp("java.class.path", PathSettings.srcSpecLib.toString + ";" + propOrElse("java.class.path", "")) true } } diff --git a/src/partest/scala/tools/partest/nest/Worker.scala b/src/partest/scala/tools/partest/nest/Worker.scala index f74182e81c..952d99c318 100644 --- a/src/partest/scala/tools/partest/nest/Worker.scala +++ b/src/partest/scala/tools/partest/nest/Worker.scala @@ -53,6 +53,8 @@ class ScalaCheckFileManager(val origmanager: FileManager) extends FileManager { var CLASSPATH: String = join(origmanager.CLASSPATH, PathSettings.scalaCheck.path) var LATEST_LIB: String = origmanager.LATEST_LIB + var LATEST_COMP: String = origmanager.LATEST_COMP + var LATEST_PARTEST: String = origmanager.LATEST_PARTEST } object Output { diff --git a/src/swing/scala/swing/test/ButtonApp.scala b/src/swing/scala/swing/test/ButtonApp.scala deleted file mode 100644 index dcf567d365..0000000000 --- a/src/swing/scala/swing/test/ButtonApp.scala +++ /dev/null @@ -1,25 +0,0 @@ -package scala.swing -package test - -import java.awt.Dimension - -import swing._ -import swing.event._ - -object ButtonApp extends SimpleSwingApplication { - def top = new MainFrame { - title = "My Frame" - contents = new GridPanel(2, 2) { - hGap = 3 - vGap = 3 - contents += new Button { - text = "Press Me!" - reactions += { - case ButtonClicked(_) => text = "Hello Scala" - } - } - } - size = new Dimension(300, 80) - } -} - diff --git a/src/swing/scala/swing/test/CelsiusConverter.scala b/src/swing/scala/swing/test/CelsiusConverter.scala deleted file mode 100644 index 4ead632d7a..0000000000 --- a/src/swing/scala/swing/test/CelsiusConverter.scala +++ /dev/null @@ -1,43 +0,0 @@ -package scala.swing -package test - -import swing._ -import event._ - -/** A GUI app to convert celsius to centigrade - */ -object CelsiusConverter extends SimpleSwingApplication { - def top = new MainFrame { - title = "Convert Celsius to Fahrenheit" - val tempCelsius = new TextField - val celsiusLabel = new Label { - text = "Celsius" - border = Swing.EmptyBorder(5, 5, 5, 5) - } - val convertButton = new Button { - text = "Convert"//new javax.swing.ImageIcon("c:\\workspace\\gui\\images\\convert.gif") - //border = Border.Empty(5, 5, 5, 5) - } - val fahrenheitLabel = new Label { - text = "Fahrenheit " - border = Swing.EmptyBorder(5, 5, 5, 5) - listenTo(convertButton, tempCelsius) - - def convert() { - val c = Integer.parseInt(tempCelsius.text) - val f = c * 9 / 5 + 32 - text = "<html><font color = red>"+f+"</font> Fahrenheit</html>" - } - - reactions += { - case ButtonClicked(_) | EditDone(_) => convert() - } - } - contents = new GridPanel(2,2) { - contents.append(tempCelsius, celsiusLabel, convertButton, fahrenheitLabel) - border = Swing.EmptyBorder(10, 10, 10, 10) - } - //defaultButton = Some(convertButton) - } -} - diff --git a/src/swing/scala/swing/test/CelsiusConverter2.scala b/src/swing/scala/swing/test/CelsiusConverter2.scala deleted file mode 100644 index 5ce1b157fe..0000000000 --- a/src/swing/scala/swing/test/CelsiusConverter2.scala +++ /dev/null @@ -1,37 +0,0 @@ -package scala.swing -package test - -import swing._ -import event._ - -object CelsiusConverter2 extends SimpleSwingApplication { - def newField = new TextField { - text = "0" - columns = 5 - horizontalAlignment = Alignment.Right - } - val celsius = newField - val fahrenheit = newField - - listenTo(fahrenheit, celsius) - reactions += { - case EditDone(`fahrenheit`) => - val f = Integer.parseInt(fahrenheit.text) - val c = (f - 32) * 5 / 9 - celsius.text = c.toString - case EditDone(`celsius`) => - val c = Integer.parseInt(celsius.text) - val f = c * 9 / 5 + 32 - fahrenheit.text = f.toString - } - - lazy val ui = new FlowPanel(celsius, new Label(" Celsius = "), - fahrenheit, new Label(" Fahrenheit")) { - border = Swing.EmptyBorder(15, 10, 10, 10) - } - def top = new MainFrame { - title = "Convert Celsius / Fahrenheit" - contents = ui - } -} - diff --git a/src/swing/scala/swing/test/ComboBoxes.scala b/src/swing/scala/swing/test/ComboBoxes.scala deleted file mode 100644 index cf1a70d97b..0000000000 --- a/src/swing/scala/swing/test/ComboBoxes.scala +++ /dev/null @@ -1,87 +0,0 @@ -package scala.swing -package test - -import swing._ -import event._ -import java.util.Date -import java.awt.Color -import java.text.SimpleDateFormat -import javax.swing.{Icon, ImageIcon} - -/** - * Demonstrates how to use combo boxes and custom item renderers. - * - * TODO: clean up layout - */ -object ComboBoxes extends SimpleSwingApplication { - import ComboBox._ - lazy val ui = new FlowPanel { - contents += new ComboBox(List(1,2,3,4)) - - val patterns = List("dd MMMMM yyyy", - "dd.MM.yy", - "MM/dd/yy", - "yyyy.MM.dd G 'at' hh:mm:ss z", - "EEE, MMM d, ''yy", - "h:mm a", - "H:mm:ss:SSS", - "K:mm a,z", - "yyyy.MMMMM.dd GGG hh:mm aaa") - val dateBox = new ComboBox(patterns) { makeEditable() } - contents += dateBox - val field = new TextField(20) { editable = false } - contents += field - - reactions += { - case SelectionChanged(`dateBox`) => reformat() - } - listenTo(dateBox.selection) - - def reformat() { - try { - val today = new Date - val formatter = new SimpleDateFormat(dateBox.selection.item) - val dateString = formatter.format(today) - field.foreground = Color.black - field.text = dateString - } catch { - case e: IllegalArgumentException => - field.foreground = Color.red - field.text = "Error: " + e.getMessage - } - } - - - val icons = try { - List(new ImageIcon(resourceFromClassloader("images/margarita1.jpg")), - new ImageIcon(resourceFromClassloader("images/margarita2.jpg")), - new ImageIcon(resourceFromClassloader("images/rose.jpg")), - new ImageIcon(resourceFromClassloader("images/banana.jpg"))) - } catch { - case _ => - println("Couldn't load images for combo box") - List(Swing.EmptyIcon) - } - - val iconBox = new ComboBox(icons) { - renderer = new ListView.AbstractRenderer[Icon, Label](new Label) { - def configure(list: ListView[_], isSelected: Boolean, focused: Boolean, icon: Icon, index: Int) { - component.icon = icon - component.xAlignment = Alignment.Center - if(isSelected) { - component.border = Swing.LineBorder(list.selectionBackground, 3) - } else { - component.border = Swing.EmptyBorder(3) - } - } - } - } - contents += iconBox - } - - def top = new MainFrame { - title = "ComboBoxes Demo" - contents = ui - } -} - diff --git a/src/swing/scala/swing/test/CountButton.scala b/src/swing/scala/swing/test/CountButton.scala deleted file mode 100644 index 373db785ba..0000000000 --- a/src/swing/scala/swing/test/CountButton.scala +++ /dev/null @@ -1,31 +0,0 @@ -package scala.swing -package test - -import scala.swing._ -import scala.swing.event._ - -object CountButton extends SimpleSwingApplication { - def top = new MainFrame { - title = "My Frame" - contents = new GridPanel(2, 2) { - hGap = 3 - vGap = 3 - val button = new Button { - text = "Press Me!" - } - contents += button - val label = new Label { - text = "No button clicks registered" - } - contents += label - - listenTo(button) - var nclicks = 0 - reactions += { - case ButtonClicked(b) => - nclicks += 1 - label.text = "Number of button clicks: "+nclicks - } - } - } -} diff --git a/src/swing/scala/swing/test/Dialogs.scala b/src/swing/scala/swing/test/Dialogs.scala deleted file mode 100644 index 14fa2febf2..0000000000 --- a/src/swing/scala/swing/test/Dialogs.scala +++ /dev/null @@ -1,177 +0,0 @@ -package scala.swing -package test - -import swing._ -import swing.event._ - -object Dialogs extends SimpleSwingApplication { - import TabbedPane._ - - lazy val label = new Label("No Result yet") - lazy val tabs = new TabbedPane { - pages += new Page("File", new GridBagPanel { grid => - import GridBagPanel._ - val buttonText = new TextField("Click Me") - - val c = new Constraints - c.fill = Fill.Horizontal - c.grid = (1,1) - - val chooser = new FileChooser - layout(new Button(Action("Open") { - chooser.showOpenDialog(grid) - })) = c - - c.grid = (1,2) - layout(new Button(Action("Save") { - chooser.showSaveDialog(grid) - })) = c - - c.grid = (1,3) - layout(new Button(Action("Custom") { - chooser.showDialog(grid, buttonText.text) - })) = c - - c.grid = (2,3) - layout(new Label(" with Text ")) = c - - c.grid = (3,3) - c.ipadx = 50 - layout(buttonText) = c - - border = Swing.EmptyBorder(5, 5, 5, 5) - }) - pages += new Page("Simple Modal Dialogs", new BorderPanel { - import BorderPanel._ - val mutex = new ButtonGroup - val ok = new RadioButton("OK (in the L&F's words)") - val ynlf = new RadioButton("Yes/No (in the L&F's words)") - val ynp = new RadioButton("Yes/No (in the programmer's words)") - val yncp = new RadioButton("Yes/No/Cancel (in the programmer's words)") - val radios = List(ok, ynlf, ynp, yncp) - mutex.buttons ++= radios - mutex.select(ok) - val buttons = new BoxPanel(Orientation.Vertical) { - contents ++= radios - } - layout(buttons) = Position.North - layout(new Button(Action("Show It!") { - import Dialog._ - mutex.selected.get match { - case `ok` => - showMessage(buttons, "Eggs aren't supposed to be green.") - case `ynlf` => - label.text = showConfirmation(buttons, - "Would you like green eggs and ham?", - "An Inane Question") match { - case Result.Yes => "Ewww!" - case Result.No => "Me neither!" - case _ => "Come on -- tell me!" - } - case `ynp` => - val options = List("Yes, please", - "No, thanks", - "No eggs, no ham!") - label.text = showOptions(buttons, - "Would you like some green eggs to go with that ham?", - "A Silly Question", - entries = options, - initial = 2) match { - case Result.Yes => "You're kidding!" - case Result.No => "I don't like them, either." - case _ => "Come on -- 'fess up!" - } - case `yncp` => - val options = List("Yes, please", - "No, thanks", - "No eggs, no ham!") - label.text = showOptions(buttons, - message = "Would you like some green eggs to go with that ham?", - title = "A Silly Question", - entries = options, - initial = 2) match { - case Result.Yes => "Here you go: green eggs and ham!" - case Result.No => "OK, just the ham, then." - case Result.Cancel => "Well, I'm certainly not going to eat them!" - case _ => "Please tell me what you want!" - } - } - })) = Position.South - }) - pages += new Page("More Dialogs", new BorderPanel { - import BorderPanel._ - val mutex = new ButtonGroup - val pick = new RadioButton("Pick one of several choices") - val enter = new RadioButton("Enter some text") - val custom = new RadioButton("Custom") - val customUndec = new RadioButton("Custom undecorated") - val custom2 = new RadioButton("2 custom dialogs") - val radios = List(pick, enter, custom, customUndec, custom2) - mutex.buttons ++= radios - mutex.select(pick) - val buttons = new BoxPanel(Orientation.Vertical) { - contents ++= radios - } - layout(buttons) = Position.North - layout(new Button(Action("Show It!") { - import Dialog._ - mutex.selected.get match { - case `pick` => - val possibilities = List("ham", "spam", "yam") - val s = showInput(buttons, - "Complete the sentence:\n\"Green eggs and...\"", - "Customized Dialog", - Message.Plain, - Swing.EmptyIcon, - possibilities, "ham") - - //If a string was returned, say so. - label.text = if ((s != None) && (s.get.length > 0)) - "Green eggs and... " + s.get + "!" - else - "Come on, finish the sentence!" - case `enter` => - val s = showInput(buttons, - "Complete the sentence:\n\"Green eggs and...\"", - "Customized Dialog", - Message.Plain, - Swing.EmptyIcon, - Nil, "ham") - - //If a string was returned, say so. - label.text = if ((s != None) && (s.get.length > 0)) - "Green eggs and... " + s.get + "!" - else - "Come on, finish the sentence!" - case `custom` => - val dialog = new Dialog(top) - dialog.open() - dialog.contents = Button("Close Me!") { dialog.close() } - case `customUndec` => - val dialog = new Dialog with RichWindow.Undecorated - dialog.open() - dialog.contents = Button("Close Me!") { dialog.close() } - case `custom2` => - val d1 = new Dialog - val d2 = new Dialog(d1) - d1.open() - d2.open() - d1.contents = Button("Close Me! I am the owner and will automatically close the other one") { d1.close() } - d2.contents = Button("Close Me!") { d2.close() } - } - })) = Position.South - }) - } - - lazy val ui: Panel = new BorderPanel { - layout(tabs) = BorderPanel.Position.Center - layout(label) = BorderPanel.Position.South - } - - - lazy val top = new MainFrame { - title = "Dialog Demo" - contents = ui - } -} - diff --git a/src/swing/scala/swing/test/GridBagDemo.scala b/src/swing/scala/swing/test/GridBagDemo.scala deleted file mode 100644 index ebb538f1c0..0000000000 --- a/src/swing/scala/swing/test/GridBagDemo.scala +++ /dev/null @@ -1,65 +0,0 @@ -package scala.swing -package test - -import swing._ -import swing.event._ -import GridBagPanel._ -import java.awt.Insets - -object GridBagDemo extends SimpleSwingApplication { - lazy val ui = new GridBagPanel { - val c = new Constraints - val shouldFill = true - if (shouldFill) { - c.fill = Fill.Horizontal - } - - val button1 = new Button("Button 1") - - c.weightx = 0.5 - - c.fill = Fill.Horizontal - c.gridx = 0; - c.gridy = 0; - layout(button1) = c - - val button2 = new Button("Button 2") - c.fill = Fill.Horizontal - c.weightx = 0.5; - c.gridx = 1; - c.gridy = 0; - layout(button2) = c - - val button3 = new Button("Button 3") - c.fill = Fill.Horizontal - c.weightx = 0.5; - c.gridx = 2; - c.gridy = 0; - layout(button3) = c - - val button4 = new Button("Long-Named Button 4") - c.fill = Fill.Horizontal - c.ipady = 40; //make this component tall - c.weightx = 0.0; - c.gridwidth = 3; - c.gridx = 0; - c.gridy = 1; - layout(button4) = c - - val button5 = new Button("5") - c.fill = Fill.Horizontal - c.ipady = 0; //reset to default - c.weighty = 1.0; //request any extra vertical space - c.anchor = Anchor.PageEnd - c.insets = new Insets(10,0,0,0); //top padding - c.gridx = 1; //aligned with button 2 - c.gridwidth = 2; //2 columns wide - c.gridy = 2; //third row - layout(button5) = c - } - - def top = new MainFrame { - title = "GridBag Demo" - contents = ui - } -} diff --git a/src/swing/scala/swing/test/HelloWorld.scala b/src/swing/scala/swing/test/HelloWorld.scala deleted file mode 100644 index 6014a14b2d..0000000000 --- a/src/swing/scala/swing/test/HelloWorld.scala +++ /dev/null @@ -1,14 +0,0 @@ -package scala.swing -package test - -import swing._ - -/** - * A simple swing demo. - */ -object HelloWorld extends SimpleSwingApplication { - def top = new MainFrame { - title = "Hello, World!" - contents = new Button("Click Me!") - } -}
\ No newline at end of file diff --git a/src/swing/scala/swing/test/LabelTest.scala b/src/swing/scala/swing/test/LabelTest.scala deleted file mode 100644 index 47eedb84ac..0000000000 --- a/src/swing/scala/swing/test/LabelTest.scala +++ /dev/null @@ -1,20 +0,0 @@ -package scala.swing -package test - -import scala.swing._ -import scala.swing.event._ - -object LabelTest extends SimpleSwingApplication { - def top = new MainFrame{ - contents = new Label { - text = "Hello" - import java.awt.event._ - listenTo(mouse.clicks) - reactions += { - case MousePressed(_,_,_,_,_) => - println("Mouse pressed2") - } - } - } -} - diff --git a/src/swing/scala/swing/test/LinePainting.scala b/src/swing/scala/swing/test/LinePainting.scala deleted file mode 100644 index 8588665ddc..0000000000 --- a/src/swing/scala/swing/test/LinePainting.scala +++ /dev/null @@ -1,54 +0,0 @@ -package scala.swing -package test - -import scala.swing.Swing._ -import scala.swing.{MainFrame, Panel} -import scala.swing.event._ -import java.awt.{Color, Graphics2D, Point, geom} - -/** - * Dragging the mouse draws a simple graph - * - * @author Frank Teubler, Ingo Maier - */ -object LinePainting extends SimpleSwingApplication { - lazy val ui = new Panel { - background = Color.white - preferredSize = (200,200) - - focusable = true - listenTo(mouse.clicks, mouse.moves, keys) - - reactions += { - case e: MousePressed => - moveTo(e.point) - requestFocusInWindow() - case e: MouseDragged => lineTo(e.point) - case e: MouseReleased => lineTo(e.point) - case KeyTyped(_,'c',_,_) => - path = new geom.GeneralPath - repaint() - case _: FocusLost => repaint() - } - - /* records the dragging */ - var path = new geom.GeneralPath - - def lineTo(p: Point) { path.lineTo(p.x, p.y); repaint() } - def moveTo(p: Point) { path.moveTo(p.x, p.y); repaint() } - - override def paintComponent(g: Graphics2D) = { - super.paintComponent(g) - g.setColor(new Color(100,100,100)) - g.drawString("Press left mouse button and drag to paint." + - (if(hasFocus) " Press 'c' to clear." else ""), 10, size.height-10) - g.setColor(Color.black) - g.draw(path) - } - } - - def top = new MainFrame { - title = "Simple Line Painting Demo" - contents = ui - } -} diff --git a/src/swing/scala/swing/test/ListViewDemo.scala b/src/swing/scala/swing/test/ListViewDemo.scala deleted file mode 100644 index 2b8c8c0719..0000000000 --- a/src/swing/scala/swing/test/ListViewDemo.scala +++ /dev/null @@ -1,18 +0,0 @@ -package scala.swing -package test - -object ListViewDemo extends SimpleSwingApplication { - def top = new MainFrame { - case class City(name: String, country: String, population: Int, capital: Boolean) - val items = List(City("Lausanne", "Switzerland", 129273, false), - City("Paris", "France", 2203817, true), - City("New York", "USA", 8363710 , false), - City("Berlin", "Germany", 3416300, true), - City("Tokio", "Japan", 12787981, true)) - import ListView._ - contents = new FlowPanel(new ScrollPane(new ListView(items) { - renderer = Renderer(_.name) - })) - //new ScrollPane(new Table(items))) - } -} diff --git a/src/swing/scala/swing/test/SimpleApplet.scala b/src/swing/scala/swing/test/SimpleApplet.scala deleted file mode 100644 index d5f17f8a40..0000000000 --- a/src/swing/scala/swing/test/SimpleApplet.scala +++ /dev/null @@ -1,19 +0,0 @@ -package scala.swing -package test - -import event._ - -class SimpleApplet extends Applet { - object ui extends UI with Reactor { - def init() = { - val button = new Button("Press here!") - val text = new TextArea("Java Version: " + util.Properties.javaVersion + "\n") - listenTo(button) - reactions += { - case ButtonClicked(_) => text.text += "Button Pressed!\n" - case _ => - } - contents = new BoxPanel(Orientation.Vertical) { contents.append(button, text) } - } - } -} diff --git a/src/swing/scala/swing/test/SwingApp.scala b/src/swing/scala/swing/test/SwingApp.scala deleted file mode 100644 index b47d778d3a..0000000000 --- a/src/swing/scala/swing/test/SwingApp.scala +++ /dev/null @@ -1,30 +0,0 @@ -package scala.swing -package test - -import swing._ -import swing.event._ - -object SwingApp extends SimpleSwingApplication { - def top = new MainFrame { - title = "SwingApp" - var numclicks = 0 - object label extends Label { - val prefix = "Number of button clicks: " - text = prefix + "0 " - listenTo(button) - reactions += { - case ButtonClicked(button) => - numclicks = numclicks + 1 - text = prefix + numclicks - } - } - object button extends Button { - text = "I am a button" - } - contents = new FlowPanel { - contents.append(button, label) - border = Swing.EmptyBorder(5, 5, 5, 5) - } - } -} - diff --git a/src/swing/scala/swing/test/TableSelection.scala b/src/swing/scala/swing/test/TableSelection.scala deleted file mode 100644 index bbfef80277..0000000000 --- a/src/swing/scala/swing/test/TableSelection.scala +++ /dev/null @@ -1,97 +0,0 @@ -package scala.swing -package test - -import java.awt.Dimension -import swing.event._ - -object TableSelection extends SimpleSwingApplication { - val model = Array(List("Mary", "Campione", "Snowboarding", 5, false).toArray, - List("Alison", "Huml", "Rowing", 5, false).toArray, - List("Kathy", "Walrath", "Knitting", 5, false).toArray, - List("Sharon", "Zakhour", "Speed reading", 5, false).toArray, - List("Philip", "Milne", "Pool", 5, false).toArray) - /*val model = Array.tabulate(10000) { i => - List("Mary", "Campione", "Snowboarding", i, false).toArray - }*/ - - lazy val ui = new BoxPanel(Orientation.Vertical) { - val table = new Table(model, Array("First Name", "Last Name", "Sport", "# of Years", "Vegetarian")) { - preferredViewportSize = new Dimension(500, 70) - } - //1.6:table.fillsViewportHeight = true - listenTo(table.selection) - - contents += new ScrollPane(table) - contents += new Label("Selection Mode") - - def radio(mutex: ButtonGroup, text: String): RadioButton = { - val b = new RadioButton(text) - listenTo(b) - mutex.buttons += b - contents += b - b - } - - val intervalMutex = new ButtonGroup - val multiInterval = radio(intervalMutex, "Multiple Interval Selection") - val elementInterval = radio(intervalMutex, "Single Selection") - val singleInterval = radio(intervalMutex, "Single Interval Selection") - intervalMutex.select(multiInterval) - - contents += new Label("Selection Options") - val elemMutex = new ButtonGroup - val rowSelection = radio(elemMutex, "Row Selection") - val columnSelection = radio(elemMutex, "Column Selection") - val cellSelection = radio(elemMutex, "Cell Selection") - elemMutex.select(rowSelection) - - val output = new TextArea(5, 40) { editable = false } - contents += new ScrollPane(output) - - def outputSelection() { - output.append("Lead: " + table.selection.rows.leadIndex + "," + - table.selection.columns.leadIndex + ". ") - output.append("Rows:") - for (c <- table.selection.rows) output.append(" " + c) - output.append(". Columns:") - for (c <- table.selection.columns) output.append(" " + c) - output.append(".\n") - } - - reactions += { - case ButtonClicked(`multiInterval`) => - table.selection.intervalMode = Table.IntervalMode.MultiInterval - if (cellSelection.selected) { - elemMutex.select(rowSelection) - table.selection.elementMode = Table.ElementMode.None - } - cellSelection.enabled = false - case ButtonClicked(`elementInterval`) => - table.selection.intervalMode = Table.IntervalMode.Single - cellSelection.enabled = true - case ButtonClicked(`singleInterval`) => - table.selection.intervalMode = Table.IntervalMode.SingleInterval - cellSelection.enabled = true - case ButtonClicked(`rowSelection`) => - if (rowSelection.selected) - table.selection.elementMode = Table.ElementMode.Row - case ButtonClicked(`columnSelection`) => - if (columnSelection.selected) - table.selection.elementMode = Table.ElementMode.Column - case ButtonClicked(`cellSelection`) => - if (cellSelection.selected) - table.selection.elementMode = Table.ElementMode.Cell - case TableRowsSelected(_, range, false) => - output.append("Rows selected, changes: " + range + "\n") - outputSelection() - case TableColumnsSelected(_, range, false) => - output.append("Columns selected, changes " + range + "\n") - outputSelection() - } - } - - def top = new MainFrame { - title = "Table Selection" - contents = ui - } -} diff --git a/src/swing/scala/swing/test/UIDemo.scala b/src/swing/scala/swing/test/UIDemo.scala deleted file mode 100644 index 9207c82948..0000000000 --- a/src/swing/scala/swing/test/UIDemo.scala +++ /dev/null @@ -1,148 +0,0 @@ -package scala.swing -package test - -import swing._ -import event._ -import Swing._ -import ListView._ - -object UIDemo extends SimpleSwingApplication { - def top = new MainFrame { - title = "Scala Swing Demo" - - /* - * Create a menu bar with a couple of menus and menu items and - * set the result as this frame's menu bar. - */ - menuBar = new MenuBar { - contents += new Menu("A Menu") { - contents += new MenuItem("An item") - contents += new MenuItem(Action("An action item") { - println("Action '"+ title +"' invoked") - }) - contents += new Separator - contents += new CheckMenuItem("Check me") - contents += new CheckMenuItem("Me too!") - contents += new Separator - val a = new RadioMenuItem("a") - val b = new RadioMenuItem("b") - val c = new RadioMenuItem("c") - val mutex = new ButtonGroup(a,b,c) - contents ++= mutex.buttons - } - contents += new Menu("Empty Menu") - } - - /* - * The root component in this frame is a panel with a border layout. - */ - contents = new BorderPanel { - import BorderPanel.Position._ - - var reactLive = false - - val tabs = new TabbedPane { - import TabbedPane._ - val buttons = new FlowPanel { - border = Swing.EmptyBorder(5,5,5,5) - - contents += new BoxPanel(Orientation.Vertical) { - border = CompoundBorder(TitledBorder(EtchedBorder, "Radio Buttons"), EmptyBorder(5,5,5,10)) - val a = new RadioButton("Green Vegetables") - val b = new RadioButton("Red Meat") - val c = new RadioButton("White Tofu") - val mutex = new ButtonGroup(a,b,c) - contents ++= mutex.buttons - } - contents += new BoxPanel(Orientation.Vertical) { - border = CompoundBorder(TitledBorder(EtchedBorder, "Check Boxes"), EmptyBorder(5,5,5,10)) - val paintLabels = new CheckBox("Paint Labels") - val paintTicks = new CheckBox("Paint Ticks") - val snapTicks = new CheckBox("Snap To Ticks") - val live = new CheckBox("Live") - contents.append(paintLabels, paintTicks, snapTicks, live) - listenTo(paintLabels, paintTicks, snapTicks, live) - reactions += { - case ButtonClicked(`paintLabels`) => - slider.paintLabels = paintLabels.selected - case ButtonClicked(`paintTicks`) => - slider.paintTicks = paintTicks.selected - case ButtonClicked(`snapTicks`) => - slider.snapToTicks = snapTicks.selected - case ButtonClicked(`live`) => - reactLive = live.selected - } - } - contents += new Button(Action("Center Frame") { centerOnScreen() }) - } - pages += new Page("Buttons", buttons) - pages += new Page("GridBag", GridBagDemo.ui) - pages += new Page("Converter", CelsiusConverter2.ui) - pages += new Page("Tables", TableSelection.ui) - pages += new Page("Dialogs", Dialogs.ui) - pages += new Page("Combo Boxes", ComboBoxes.ui) - pages += new Page("Split Panes", - new SplitPane(Orientation.Vertical, new Button("Hello"), new Button("World")) { - continuousLayout = true - }) - - val password = new FlowPanel { - contents += new Label("Enter your secret password here ") - val field = new PasswordField(10) - contents += field - val label = new Label(field.text) - contents += label - listenTo(field) - reactions += { - case EditDone(`field`) => label.text = field.password.mkString - } - } - - pages += new Page("Password", password) - pages += new Page("Painting", LinePainting.ui) - //pages += new Page("Text Editor", TextEditor.ui) - } - - val list = new ListView(tabs.pages) { - selectIndices(0) - selection.intervalMode = ListView.IntervalMode.Single - renderer = ListView.Renderer(_.title) - } - val center = new SplitPane(Orientation.Vertical, new ScrollPane(list), tabs) { - oneTouchExpandable = true - continuousLayout = true - } - layout(center) = Center - - /* - * This slider is used above, so we need lazy initialization semantics. - * Objects or lazy vals are the way to go, but objects give us better - * type inference at times. - */ - object slider extends Slider { - min = 0 - value = tabs.selection.index - max = tabs.pages.size-1 - majorTickSpacing = 1 - } - layout(slider) = South - - /* - * Establish connection between the tab pane, slider, and list view. - */ - listenTo(slider) - listenTo(tabs.selection) - listenTo(list.selection) - reactions += { - case ValueChanged(`slider`) => - if(!slider.adjusting || reactLive) tabs.selection.index = slider.value - case SelectionChanged(`tabs`) => - slider.value = tabs.selection.index - list.selectIndices(tabs.selection.index) - case SelectionChanged(`list`) => - if (list.selection.items.length == 1) - tabs.selection.page = list.selection.items(0) - } - } - } -}
\ No newline at end of file diff --git a/src/swing/scala/swing/test/images/banana.jpg b/src/swing/scala/swing/test/images/banana.jpg Binary files differdeleted file mode 100644 index 62267a4325..0000000000 --- a/src/swing/scala/swing/test/images/banana.jpg +++ /dev/null diff --git a/src/swing/scala/swing/test/images/margarita1.jpg b/src/swing/scala/swing/test/images/margarita1.jpg Binary files differdeleted file mode 100644 index d315f7c79f..0000000000 --- a/src/swing/scala/swing/test/images/margarita1.jpg +++ /dev/null diff --git a/src/swing/scala/swing/test/images/margarita2.jpg b/src/swing/scala/swing/test/images/margarita2.jpg Binary files differdeleted file mode 100644 index c8b076e5f9..0000000000 --- a/src/swing/scala/swing/test/images/margarita2.jpg +++ /dev/null diff --git a/src/swing/scala/swing/test/images/rose.jpg b/src/swing/scala/swing/test/images/rose.jpg Binary files differdeleted file mode 100644 index d4a2b58062..0000000000 --- a/src/swing/scala/swing/test/images/rose.jpg +++ /dev/null |