diff options
178 files changed, 3642 insertions, 1786 deletions
@@ -941,9 +941,6 @@ PACKED QUICK BUILD (PACK) <fileset dir="${build-quick.dir}/classes/library"> <include name="scala/swing/**"/> </fileset> - <fileset dir="${src.dir}/swing"> - <include name="scala/swing/test/images/**"/> - </fileset> </jar> </target> @@ -1543,7 +1540,6 @@ DOCUMENTATION <exclude name="runtime/*$.scala"/> <exclude name="runtime/ScalaRunTime.scala"/> <exclude name="runtime/StringAdd.scala"/> - <exclude name="scala/swing/test/**"/> </scaladoc> <touch file="${build-docs.dir}/library.complete" verbose="no"/> <stopwatch name="docs.lib.timer" action="total"/> diff --git a/src/swing/scala/swing/test/ButtonApp.scala b/docs/examples/swing/ButtonApp.scala index dcf567d365..96799b24f2 100644 --- a/src/swing/scala/swing/test/ButtonApp.scala +++ b/docs/examples/swing/ButtonApp.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import java.awt.Dimension diff --git a/src/swing/scala/swing/test/CelsiusConverter.scala b/docs/examples/swing/CelsiusConverter.scala index 4ead632d7a..b4a62fb366 100644 --- a/src/swing/scala/swing/test/CelsiusConverter.scala +++ b/docs/examples/swing/CelsiusConverter.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import swing._ import event._ diff --git a/src/swing/scala/swing/test/CelsiusConverter2.scala b/docs/examples/swing/CelsiusConverter2.scala index 5ce1b157fe..3630d61b61 100644 --- a/src/swing/scala/swing/test/CelsiusConverter2.scala +++ b/docs/examples/swing/CelsiusConverter2.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import swing._ import event._ diff --git a/src/swing/scala/swing/test/ComboBoxes.scala b/docs/examples/swing/ComboBoxes.scala index cf1a70d97b..c6ee19013a 100644 --- a/src/swing/scala/swing/test/ComboBoxes.scala +++ b/docs/examples/swing/ComboBoxes.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import swing._ import event._ diff --git a/src/swing/scala/swing/test/CountButton.scala b/docs/examples/swing/CountButton.scala index 373db785ba..5fb14681d6 100644 --- a/src/swing/scala/swing/test/CountButton.scala +++ b/docs/examples/swing/CountButton.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import scala.swing._ import scala.swing.event._ diff --git a/src/swing/scala/swing/test/Dialogs.scala b/docs/examples/swing/Dialogs.scala index 14fa2febf2..0b4ac258cf 100644 --- a/src/swing/scala/swing/test/Dialogs.scala +++ b/docs/examples/swing/Dialogs.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import swing._ import swing.event._ diff --git a/src/swing/scala/swing/test/GridBagDemo.scala b/docs/examples/swing/GridBagDemo.scala index ebb538f1c0..60cfc13acb 100644 --- a/src/swing/scala/swing/test/GridBagDemo.scala +++ b/docs/examples/swing/GridBagDemo.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import swing._ import swing.event._ diff --git a/src/swing/scala/swing/test/HelloWorld.scala b/docs/examples/swing/HelloWorld.scala index 6014a14b2d..e89bfedd8a 100644 --- a/src/swing/scala/swing/test/HelloWorld.scala +++ b/docs/examples/swing/HelloWorld.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import swing._ @@ -11,4 +10,4 @@ object HelloWorld extends SimpleSwingApplication { 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/docs/examples/swing/LabelTest.scala index 47eedb84ac..edd7a14634 100644 --- a/src/swing/scala/swing/test/LabelTest.scala +++ b/docs/examples/swing/LabelTest.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import scala.swing._ import scala.swing.event._ diff --git a/src/swing/scala/swing/test/LinePainting.scala b/docs/examples/swing/LinePainting.scala index 8588665ddc..f72f8701ed 100644 --- a/src/swing/scala/swing/test/LinePainting.scala +++ b/docs/examples/swing/LinePainting.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import scala.swing.Swing._ import scala.swing.{MainFrame, Panel} diff --git a/src/swing/scala/swing/test/ListViewDemo.scala b/docs/examples/swing/ListViewDemo.scala index 2b8c8c0719..5630f2871d 100644 --- a/src/swing/scala/swing/test/ListViewDemo.scala +++ b/docs/examples/swing/ListViewDemo.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing object ListViewDemo extends SimpleSwingApplication { def top = new MainFrame { diff --git a/src/swing/scala/swing/test/SimpleApplet.scala b/docs/examples/swing/SimpleApplet.scala index d5f17f8a40..502de537a3 100644 --- a/src/swing/scala/swing/test/SimpleApplet.scala +++ b/docs/examples/swing/SimpleApplet.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import event._ diff --git a/src/swing/scala/swing/test/SwingApp.scala b/docs/examples/swing/SwingApp.scala index b47d778d3a..b3fe7447ef 100644 --- a/src/swing/scala/swing/test/SwingApp.scala +++ b/docs/examples/swing/SwingApp.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import swing._ import swing.event._ diff --git a/src/swing/scala/swing/test/TableSelection.scala b/docs/examples/swing/TableSelection.scala index bbfef80277..8c8ea4ffcc 100644 --- a/src/swing/scala/swing/test/TableSelection.scala +++ b/docs/examples/swing/TableSelection.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import java.awt.Dimension import swing.event._ diff --git a/src/swing/scala/swing/test/UIDemo.scala b/docs/examples/swing/UIDemo.scala index 9207c82948..6d77c049e0 100644 --- a/src/swing/scala/swing/test/UIDemo.scala +++ b/docs/examples/swing/UIDemo.scala @@ -1,5 +1,4 @@ -package scala.swing -package test +package examples.swing import swing._ import event._ @@ -145,4 +144,4 @@ object UIDemo extends SimpleSwingApplication { } } } -}
\ No newline at end of file +} diff --git a/src/swing/scala/swing/test/images/banana.jpg b/docs/examples/swing/images/banana.jpg Binary files differindex 62267a4325..62267a4325 100644 --- a/src/swing/scala/swing/test/images/banana.jpg +++ b/docs/examples/swing/images/banana.jpg diff --git a/src/swing/scala/swing/test/images/margarita1.jpg b/docs/examples/swing/images/margarita1.jpg Binary files differindex d315f7c79f..d315f7c79f 100644 --- a/src/swing/scala/swing/test/images/margarita1.jpg +++ b/docs/examples/swing/images/margarita1.jpg diff --git a/src/swing/scala/swing/test/images/margarita2.jpg b/docs/examples/swing/images/margarita2.jpg Binary files differindex c8b076e5f9..c8b076e5f9 100644 --- a/src/swing/scala/swing/test/images/margarita2.jpg +++ b/docs/examples/swing/images/margarita2.jpg diff --git a/src/swing/scala/swing/test/images/rose.jpg b/docs/examples/swing/images/rose.jpg Binary files differindex d4a2b58062..d4a2b58062 100644 --- a/src/swing/scala/swing/test/images/rose.jpg +++ b/docs/examples/swing/images/rose.jpg 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 aee3938715..d38b62cbb4 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -14,6 +14,16 @@ 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 => @@ -66,13 +76,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 +127,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 +193,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 +205,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 } @@ -267,10 +269,11 @@ trait Definitions extends reflect.api.StandardDefinitions { (sym.name == name) && (sym.owner == PredefModule.moduleClass) ) - lazy val ConsoleModule: Symbol = getRequiredModule("scala.Console") + lazy val ConsoleModule: Symbol = getRequiredModule("scala.Console") lazy val ScalaRunTimeModule: Symbol = getRequiredModule("scala.runtime.ScalaRunTime") - lazy val SymbolModule: Symbol = getRequiredModule("scala.Symbol") - lazy val Symbol_apply = getMember(SymbolModule, nme.apply) + lazy val SymbolModule: Symbol = getRequiredModule("scala.Symbol") + lazy val Symbol_apply = SymbolModule.info decl nme.apply + def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq) def arrayApplyMethod = getMember(ScalaRunTimeModule, nme.array_apply) def arrayUpdateMethod = getMember(ScalaRunTimeModule, nme.array_update) @@ -295,7 +298,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") @@ -442,15 +445,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 @@ -594,6 +593,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)) @@ -808,13 +810,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 @@ -831,24 +826,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 = @@ -856,16 +835,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 @@ -965,12 +942,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: @@ -981,26 +958,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 @@ -1037,7 +1012,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 6683778671..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) { @@ -167,7 +169,7 @@ trait Importers { self: SymbolTable => case from.AntiPolyType(pre, targs) => AntiPolyType(importType(pre), targs map importType) case x: from.TypeVar => - new TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol) + TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol) case from.NotNullType(tpe) => NotNullType(importType(tpe)) case from.AnnotatedType(annots, tpe, selfsym) => diff --git a/src/compiler/scala/reflect/internal/Kinds.scala b/src/compiler/scala/reflect/internal/Kinds.scala index 15fcb5f94d..e675be43dc 100644 --- a/src/compiler/scala/reflect/internal/Kinds.scala +++ b/src/compiler/scala/reflect/internal/Kinds.scala @@ -110,10 +110,7 @@ trait Kinds { ): List[(Type, Symbol, KindErrors)] = { // instantiate type params that come from outside the abstract type we're currently checking - def transform(tp: Type, clazz: Symbol): Type = - tp.asSeenFrom(pre, clazz) - def transformedBounds(p: Symbol, o: Symbol) = - transform(p.info.instantiateTypeParams(tparams, targs).bounds, o) + def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz) // check that the type parameters hkargs to a higher-kinded type conform to the // expected params hkparams @@ -131,6 +128,7 @@ trait Kinds { // @M sometimes hkargs != arg.typeParams, the symbol and the type may // have very different type parameters val hkparams = param.typeParams + def kindCheck(cond: Boolean, f: KindErrors => KindErrors) { if (!cond) kindErrors = f(kindErrors) @@ -160,8 +158,8 @@ trait Kinds { // conceptually the same. Could also replace the types by // polytypes, but can't just strip the symbols, as ordering // is lost then. - val declaredBounds = transformedBounds(hkparam, paramowner) - val declaredBoundsInst = bindHKParams(declaredBounds) + val declaredBounds = transform(hkparam.info.instantiateTypeParams(tparams, targs).bounds, paramowner) + val declaredBoundsInst = transform(bindHKParams(declaredBounds), owner) val argumentBounds = transform(hkarg.info.bounds, owner) kindCheck(declaredBoundsInst <:< argumentBounds, _ strictnessError (hkarg -> hkparam)) diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index db1cf7f257..507621ea42 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -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" @@ -295,7 +321,6 @@ 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" @@ -578,6 +603,9 @@ trait StdNames extends NameManglers { self: SymbolTable => val testLessOrEqualThan: NameType = "testLessOrEqualThan" val testLessThan: NameType = "testLessThan" val testNotEqual: NameType = "testNotEqual" + + val isBoxedNumberOrBoolean: NameType = "isBoxedNumberOrBoolean" + val isBoxedNumber: NameType = "isBoxedNumber" def toUnaryName(name: TermName): TermName = name match { case raw.MINUS => UNARY_- @@ -628,6 +656,21 @@ trait StdNames extends NameManglers { self: SymbolTable => case _ => NO_NAME } + val reflPolyCacheName: NameType = "reflPoly$Cache" + val reflClassCacheName: NameType = "reflClass$Cache" + val reflParamsCacheName: NameType = "reflParams$Cache" + val reflMethodCacheName: NameType = "reflMethod$Cache" + val reflMethodName: NameType = "reflMethod$Method" + + private val reflectionCacheNames = Set[NameType]( + reflPolyCacheName, + reflClassCacheName, + reflParamsCacheName, + reflMethodCacheName, + reflMethodName + ) + def isReflectionCacheName(name: Name) = reflectionCacheNames exists (name startsWith _) + @switch def productAccessorName(j: Int): TermName = j match { case 1 => nme._1 case 2 => nme._2 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..b4d2b1531f 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) + } + + /** 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(pos: Position, name: TypeName): Symbol = - newAbstractType(pos, name).setFlag(EXISTENTIAL) + 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 -------------------------------------------------- @@ -1402,6 +1458,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 +2054,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 +2088,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 +2154,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 +2166,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 +2184,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 +2304,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 +2345,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 +2384,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 +2403,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 +2467,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 +2493,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 } } @@ -2443,10 +2545,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => 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 } @@ -2518,17 +2621,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 4ca55f53ea..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 = @@ -248,10 +252,13 @@ trait Trees extends api.Trees { self: SymbolTable => /** Block factory that flattens directly nested blocks. */ - def Block(stats: Tree*): Block = stats match { - case Seq(b @ Block(_, _)) => b - case Seq(stat) => Block(stats.toList, Literal(Constant(()))) - case Seq(_, rest @ _*) => Block(stats.init.toList, stats.last) + def Block(stats: Tree*): Block = { + if (stats.isEmpty) Block(Nil, Literal(Constant(()))) + else stats match { + case Seq(b @ Block(_, _)) => b + case Seq(stat) => Block(stats.toList, Literal(Constant(()))) + case Seq(_, rest @ _*) => Block(stats.init.toList, stats.last) + } } // --- specific traversers and transformers diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 6b5ba05c6d..73f1f3db84 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -87,8 +87,13 @@ trait Types extends api.Types { self: SymbolTable => private final def decr(depth: Int) = if (depth == AnyDepth) AnyDepth else depth - 1 private final val printLubs = sys.props contains "scalac.debug.lub" + private final val traceTypeVars = sys.props contains "scalac.debug.tvar" /** In case anyone wants to turn off lub verification without reverting anything. */ private final val verifyLubs = true + /** In case anyone wants to turn off type parameter bounds being used + * to seed type constraints. + */ + private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints" protected val enableTypeVarExperimentals = settings.Xexperimental.value @@ -317,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 */ @@ -407,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. */ @@ -926,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) @@ -1313,6 +1312,7 @@ trait Types extends api.Types { self: SymbolTable => case TypeBounds(_, _) => that <:< this case _ => lo <:< that && that <:< hi } + def isEmptyBounds = (lo.typeSymbolDirect eq NothingClass) && (hi.typeSymbolDirect eq AnyClass) // override def isNullable: Boolean = NullClass.tpe <:< lo; override def safeToString = ">: " + lo + " <: " + hi override def kind = "TypeBoundsType" @@ -1498,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 @@ -1644,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) @@ -1753,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 @@ -1888,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 { @@ -2009,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 @@ -2038,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) @@ -2048,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)) "" @@ -2067,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 @@ -2087,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 } @@ -2120,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. @@ -2314,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) => @@ -2404,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 @@ -2431,51 +2455,54 @@ A type's typeSymbol should never be inspected directly. // but pattern-matching returned the original constr0 (a bug) // now, pattern-matching returns the most recent constr object TypeVar { - // encapsulate suspension so we can automatically link the suspension of cloned - // typevars to their original if this turns out to be necessary -/* - def Suspension = new Suspension - class Suspension { - private val suspended = mutable.HashSet[TypeVar]() - def suspend(tv: TypeVar): Unit = { - tv.suspended = true - suspended += tv - } - def resumeAll(): Unit = { - for (tv <- suspended) { - tv.suspended = false + @inline final def trace[T](action: String, msg: => String)(value: T): T = { + if (traceTypeVars) { + val s = msg match { + case "" => "" + case str => "( " + str + " )" } - suspended.clear() + Console.err.println("[%10s] %-25s%s".format(action, value, s)) } + value } -*/ - def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr)) - def apply(origin: Type, constr: TypeConstraint) = new TypeVar(origin, constr, List(), List()) - // See pos/tcpoly_infer_implicit_tuple_wrapper for the test which - // fails if I initialize the type constraint with the type parameter - // bounds. It seems that in that instance it interferes with the - // inference. Thus, the isHigherOrderTypeParameter condition. - def apply(tparam: Symbol) = { - val constr = ( - if (tparam.isAbstractType && tparam.typeParams.nonEmpty) { - // Force the info of a higher-order tparam's parameters. - // Otherwise things don't end well. See SI-5359. - val info = tparam.info - if (info.bounds exists (t => t.typeSymbol.isHigherOrderTypeParameter)) { - log("TVar(" + tparam + ") receives empty constraint due to higher order type parameter in bounds " + info.bounds) - new TypeConstraint - } - else { - log("TVar(" + tparam + ") constraint initialized with bounds " + info.bounds) - new TypeConstraint(info.bounds) - } - } - else new TypeConstraint + + /** Create a new TypeConstraint based on the given symbol. + */ + private def deriveConstraint(tparam: Symbol): TypeConstraint = { + /** Must force the type parameter's info at this point + * or things don't end well for higher-order type params. + * See SI-5359. + */ + val bounds = tparam.info.bounds + /** We can seed the type constraint with the type parameter + * bounds as long as the types are concrete. This should lower + * the complexity of the search even if it doesn't improve + * any results. + */ + if (propagateParameterBoundsToTypeVars) { + val exclude = bounds.isEmptyBounds || bounds.exists(_.typeSymbolDirect.isNonClassType) + + if (exclude) new TypeConstraint + else TypeVar.trace("constraint", "For " + tparam.fullLocationString)(new TypeConstraint(bounds)) + } + else new TypeConstraint + } + def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr)) + def apply(origin: Type, constr: TypeConstraint): TypeVar = apply(origin, constr, Nil, Nil) + def apply(tparam: Symbol): TypeVar = apply(tparam.tpeHK, deriveConstraint(tparam), Nil, tparam.typeParams) + + /** This is the only place TypeVars should be instantiated. + */ + def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]): TypeVar = { + val tv = ( + if (args.isEmpty && params.isEmpty) new TypeVar(origin, constr) + else if (args.size == params.size) new AppliedTypeVar(origin, constr, params zip args) + else if (args.isEmpty) new HKTypeVar(origin, constr, params) + else throw new TypeError("Invalid TypeVar construction: " + ((origin, constr, args, params))) ) - new TypeVar(tparam.tpeHK, constr, Nil, tparam.typeParams) + + trace("create", "In " + tv.originLocation)(tv) } - def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]) = - new TypeVar(origin, constr, args, params) } // TODO: I don't really know why this happens -- maybe because @@ -2502,22 +2529,53 @@ A type's typeSymbol should never be inspected directly. tp.typeSymbol ) + /** Precondition: params.nonEmpty. (args.nonEmpty enforced structurally.) + */ + class HKTypeVar( + _origin: Type, + _constr: TypeConstraint, + override val params: List[Symbol] + ) extends TypeVar(_origin, _constr) { + + require(params.nonEmpty, this) + override def isHigherKinded = true + override protected def typeVarString = params.map(_.name).mkString("[", ", ", "]=>" + originName) + } + + /** Precondition: zipped params/args nonEmpty. (Size equivalence enforced structurally.) + */ + class AppliedTypeVar( + _origin: Type, + _constr: TypeConstraint, + zippedArgs: List[(Symbol, Type)] + ) extends TypeVar(_origin, _constr) { + + require(zippedArgs.nonEmpty, this) + + override def params: List[Symbol] = zippedArgs map (_._1) + override def typeArgs: List[Type] = zippedArgs map (_._2) + + override protected def typeVarString = ( + zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]") + ) + } + /** A class representing a type variable: not used after phase `typer`. * * A higher-kinded TypeVar has params (Symbols) and typeArgs (Types). * A TypeVar with nonEmpty typeArgs can only be instantiated by a higher-kinded * type that can be applied to those args. A TypeVar is much like a TypeRef, * except it has special logic for equality and subtyping. + * + * Precondition for this class, enforced structurally: args.isEmpty && params.isEmpty. */ class TypeVar( val origin: Type, - val constr0: TypeConstraint, - override val typeArgs: List[Type], - override val params: List[Symbol] + val constr0: TypeConstraint ) extends Type { - // params are needed to keep track of variance (see mapOverArgs in SubstMap) - assert(typeArgs.isEmpty || sameLength(typeArgs, params), - "%s / params=%s / args=%s".format(origin, params, typeArgs)) + override def params: List[Symbol] = Nil + override def typeArgs: List[Type] = Nil + override def isHigherKinded = false /** The constraint associated with the variable */ var constr = constr0 @@ -2525,7 +2583,38 @@ A type's typeSymbol should never be inspected directly. /** The variable's skolemization level */ val level = skolemizationLevel - + + /** Two occurrences of a higher-kinded typevar, e.g. `?CC[Int]` and `?CC[String]`, correspond to + * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`. + * + * `constr` for `?CC` only tracks type constructors anyway, + * so when `?CC[Int] <:< List[Int]` and `?CC[String] <:< Iterable[String]` + * `?CC's` hibounds contains List and Iterable. + */ + def applyArgs(newArgs: List[Type]): TypeVar = ( + if (newArgs.isEmpty && typeArgs.isEmpty) + this + else if (newArgs.size == params.size) { + val tv = TypeVar(origin, constr, newArgs, params) + TypeVar.trace("applyArgs", "In " + originLocation + ", apply args " + newArgs.mkString(", ") + " to " + originName)(tv) + } + else + throw new TypeError("Invalid type application in TypeVar: " + params + ", " + newArgs) + ) + // newArgs.length may differ from args.length (could've been empty before) + // + // !!! @PP - I need an example of this, since this exception never triggers + // even though I am requiring the size match. + // + // example: when making new typevars, you start out with C[A], then you replace C by ?C, which should yield ?C[A], then A by ?A, ?C[?A] + // we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver) + // TypeVars get applied to different arguments over time (in asSeenFrom) + // -- see pos/tcpoly_infer_implicit_tuplewrapper.scala + // thus: make new TypeVar's for every application of a TV to args, + // inference may generate several TypeVar's for a single type parameter that must be inferred, + // only one of them is in the set of tvars that need to be solved, but + // they share the same TypeConstraint instance + // When comparing to types containing skolems, remember the highest level // of skolemization. If that highest level is higher than our initial // skolemizationLevel, we can't re-use those skolems as the solution of this @@ -2536,26 +2625,6 @@ A type's typeSymbol should never be inspected directly. private var encounteredHigherLevel = false private def shouldRepackType = enableTypeVarExperimentals && encounteredHigherLevel - /** Two occurrences of a higher-kinded typevar, e.g. `?CC[Int]` and `?CC[String]`, correspond to - * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`. - * - * `constr` for `?CC` only tracks type constructors anyway, - * so when `?CC[Int] <:< List[Int]` and `?CC[String] <:< Iterable[String]` - * `?CC's` hibounds contains List and Iterable. - */ - def applyArgs(newArgs: List[Type]): TypeVar = - if (newArgs.isEmpty) this // SubstMap relies on this (though this check is redundant when called from appliedType...) - else TypeVar(origin, constr, newArgs, params) // @M TODO: interaction with undoLog?? - // newArgs.length may differ from args.length (could've been empty before) - // example: when making new typevars, you start out with C[A], then you replace C by ?C, which should yield ?C[A], then A by ?A, ?C[?A] - // we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver) - // TypeVars get applied to different arguments over time (in asSeenFrom) - // -- see pos/tcpoly_infer_implicit_tuplewrapper.scala - // thus: make new TypeVar's for every application of a TV to args, - // inference may generate several TypeVar's for a single type parameter that must be inferred, - // only one of them is in the set of tvars that need to be solved, but - // they share the same TypeConstraint instance - // <region name="constraint mutators + undoLog"> // invariant: before mutating constr, save old state in undoLog // (undoLog is used to reset constraints to avoid piling up unrelated ones) @@ -2564,7 +2633,8 @@ A type's typeSymbol should never be inspected directly. undoLog record this // if we were compared against later typeskolems, repack the existential, // because skolems are only compatible if they were created at the same level - constr.inst = if (shouldRepackType) repackExistential(tp) else tp + val res = if (shouldRepackType) repackExistential(tp) else tp + constr.inst = TypeVar.trace("setInst", "In " + originLocation + ", " + originName + "=" + res)(res) } def addLoBound(tp: Type, isNumericBound: Boolean = false) { @@ -2641,11 +2711,10 @@ A type's typeSymbol should never be inspected directly. * type parameter we're trying to infer (the result will be sanity-checked later). */ def unifyFull(tpe: Type) = { - // Since the alias/widen variations are often no-ops, this - // keenly collects them in a Set to avoid redundant tests. + // The alias/widen variations are often no-ops. val tpes = ( - if (isLowerBound) Set(tpe, tpe.widen, tpe.dealias, tpe.widen.dealias) - else Set(tpe) + if (isLowerBound) List(tpe, tpe.widen, tpe.dealias, tpe.widen.dealias).distinct + else List(tpe) ) tpes exists { tp => val lhs = if (isLowerBound) tp.typeArgs else typeArgs @@ -2745,33 +2814,56 @@ A type's typeSymbol should never be inspected directly. || !containsSkolemAboveLevel(tp) // side-effects tracking boolean || enableTypeVarExperimentals // -Xexperimental: always say we're relatable, track consequences ) - override val isHigherKinded = typeArgs.isEmpty && params.nonEmpty - override def normalize: Type = + override def normalize: Type = ( if (constr.instValid) constr.inst // get here when checking higher-order subtyping of the typevar by itself // TODO: check whether this ever happens? else if (isHigherKinded) typeFun(params, applyArgs(params map (_.typeConstructor))) else super.normalize - + ) override def typeSymbol = origin.typeSymbol override def isStable = origin.isStable override def isVolatile = origin.isVolatile + private def tparamsOfSym(sym: Symbol) = sym.info match { + case PolyType(tparams, _) if tparams.nonEmpty => + tparams map (_.defString) mkString("[", ",", "]") + case _ => "" + } + def originName = { + val name = origin.typeSymbolDirect.decodedName + if (name contains "_$") origin.typeSymbolDirect.decodedName else name + } + def originLocation = { + val sym = origin.typeSymbolDirect + val encl = sym.owner.logicallyEnclosingMember + + // This should display somewhere between one and three + // things which enclose the origin: at most, a class, a + // a method, and a term. At least, a class. + List( + Some(encl.enclClass), + if (encl.isMethod) Some(encl) else None, + if (sym.owner.isTerm && (sym.owner != encl)) Some(sym.owner) else None + ).flatten map (s => s.decodedName + tparamsOfSym(s)) mkString "#" + } private def levelString = if (settings.explaintypes.value) level else "" + protected def typeVarString = originName override def safeToString = ( - if (constr eq null) "TVar<%s,constr=null>".format(origin) - else if (constr.inst eq null) "TVar<%s,constr.inst=null>".format(origin) - else if (constr.inst eq NoType) "?" + levelString + origin + typeArgsString(this) - else "" + constr.inst + if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>" + else if (constr.inst ne NoType) "" + constr.inst + else "?" + levelString + originName ) override def kind = "TypeVar" def cloneInternal = { // cloning a suspended type variable when it's suspended will cause the clone // to never be resumed with the current implementation - assert(!suspended) - TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params? + assert(!suspended, this) + TypeVar.trace("clone", originLocation)( + TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params? + ) } } @@ -3224,8 +3316,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)) @@ -3271,8 +3363,14 @@ A type's typeSymbol should never be inspected directly. def this(bounds: TypeBounds) = this(List(bounds.lo), List(bounds.hi)) def this() = this(List(), List()) - private var lobounds = lo0 - private var hibounds = hi0 + /** Guard these lists against AnyClass and NothingClass appearing, + * else loBounds.isEmpty will have different results for an empty + * constraint and one with Nothing as a lower bound. [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) private var numlo = numlo0 private var numhi = numhi0 private var avoidWidening = avoidWidening0 @@ -3326,10 +3424,18 @@ A type's typeSymbol should never be inspected directly. tc } - override def toString = - (loBounds map (_.safeToString)).mkString("[ _>:(", ",", ") ") + - (hiBounds map (_.safeToString)).mkString("| _<:(", ",", ") ] _= ") + - inst.safeToString + override def toString = { + val boundsStr = ( + if (loBounds.isEmpty && hiBounds.isEmpty) "[]" + else { + val lostr = if (loBounds.isEmpty) "" else loBounds map (_.safeToString) mkString("_>:(", ", ", ")") + val histr = if (hiBounds.isEmpty) "" else hiBounds map (_.safeToString) mkString("_<:(", ", ", ")") + List(lostr, histr) filterNot (_ == "") mkString ("[", " | ", "]") + } + ) + if (inst eq NoType) boundsStr + else boundsStr + " _= " + inst.safeToString + } } trait AnnotationFilter extends TypeMap { @@ -3394,7 +3500,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) @@ -3407,7 +3513,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) } @@ -3422,37 +3528,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 @@ -3644,7 +3726,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)) } @@ -3766,10 +3848,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() @@ -4123,7 +4205,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) @@ -4511,7 +4593,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 { @@ -5451,10 +5533,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) @@ -5814,7 +5892,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))) } } @@ -6014,6 +6092,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..61b03a9a29 100644 --- a/src/compiler/scala/reflect/runtime/JavaToScala.scala +++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala @@ -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/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/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index c388a62644..c8db996de2 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 = 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..ce41bc456e 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 => 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..15b4c8c708 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -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..3e8ef3f611 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -102,11 +102,21 @@ abstract class Inliners extends SubComponent { 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) { + analyzeMethod(im) + } + } } - val tfa = new analysis.MethodTFA() + val tfa = new analysis.MTFAGrowable() tfa.stat = global.opt.printStats + val staleOut = new mutable.ListBuffer[BasicBlock] + val splicedBlocks = mutable.Set.empty[BasicBlock] + val staleIn = mutable.Set.empty[BasicBlock] // how many times have we already inlined this method here? private val inlinedMethodCount = perRunCaches.newMap[Symbol, Int]() withDefaultValue 0 @@ -208,34 +218,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) @@ -343,12 +354,15 @@ abstract class Inliners extends SubComponent { * 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) @@ -400,7 +414,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 @@ -478,7 +492,8 @@ abstract class Inliners extends SubComponent { block.close // duplicate the other blocks in the callee - inc.m.linearizedBlocks() foreach { bb => + val calleeLin = inc.m.linearizedBlocks() + calleeLin foreach { bb => var info = a in bb def emitInlined(i: Instruction) = inlinedBlock(bb).emit(i, targetPos) def emitDrops(toDrop: Int) = info.stack.types drop toDrop foreach (t => emitInlined(DROP(t))) @@ -503,6 +518,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) 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/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/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 ac72b4d22c..099145d3ae 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 @@ -439,9 +442,10 @@ abstract class ClassfileParser { /** Return the class symbol of the given name. */ def classNameToSymbol(name: Name): Symbol = { - def loadClassSymbol(name: Name) = { + def loadClassSymbol(name: Name): Symbol = { val file = global.classPath findSourceFile ("" +name) getOrElse { - MissingRequirementError.notFound("class " + name) + warning("Class " + name + " not found - continuing with a stub.") + return NoSymbol.newClass(name.toTypeName) } val completer = new global.loaders.ClassfileLoader(file) var owner: Symbol = definitions.RootClass @@ -454,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 } @@ -464,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 } } @@ -498,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 @@ -603,13 +605,13 @@ abstract class ClassfileParser { def parseField() { val jflags = in.nextChar - var sflags = toScalaFlags(jflags, isField = true) + var sflags = toScalaFieldFlags(jflags) if ((sflags & PRIVATE) != 0L && !global.settings.XO.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 { @@ -634,7 +636,7 @@ abstract class ClassfileParser { def parseMethod() { val jflags = in.nextChar.toInt - var sflags = toScalaFlags(jflags) + var sflags = toScalaMethodFlags(jflags) if (isPrivate(jflags) && !global.settings.XO.value) { val name = pool.getName(in.nextChar) if (name == nme.CONSTRUCTOR) @@ -647,7 +649,7 @@ abstract class ClassfileParser { 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 { @@ -717,10 +719,15 @@ abstract class ClassfileParser { index += 1 val bounds = variance match { case '+' => TypeBounds.upper(objToAny(sig2type(tparams, skiptvs))) - case '-' => TypeBounds.lower(sig2type(tparams, skiptvs)) + case '-' => + val tp = sig2type(tparams, skiptvs) + // sig2type seems to return AnyClass regardless of the situation: + // we don't want Any as a LOWER bound. + if (tp.typeSymbol == definitions.AnyClass) TypeBounds.empty + 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 @@ -807,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 @@ -1068,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..8f5d308b8f 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -121,8 +121,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 +250,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 575e3a9141..50e6139e65 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -22,9 +22,35 @@ abstract class CleanUp extends Transform with ast.TreeDSL { new CleanUpTransformer(unit) class CleanUpTransformer(unit: CompilationUnit) extends Transformer { - private val newStaticMembers = mutable.Buffer.empty[Tree] - private val newStaticInits = mutable.Buffer.empty[Tree] + private val newStaticMembers = mutable.Buffer.empty[Tree] + private val newStaticInits = mutable.Buffer.empty[Tree] private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol] + private def clearStatics() { + newStaticMembers.clear() + newStaticInits.clear() + symbolsStoredAsStatic.clear() + } + private def savingStatics[T](body: => T): T = { + val savedNewStaticMembers : mutable.Buffer[Tree] = newStaticMembers.clone() + val savedNewStaticInits : mutable.Buffer[Tree] = newStaticInits.clone() + val savedSymbolsStoredAsStatic : mutable.Map[String, Symbol] = symbolsStoredAsStatic.clone() + val result = body + + clearStatics() + newStaticMembers ++= savedNewStaticMembers + newStaticInits ++= savedNewStaticInits + symbolsStoredAsStatic ++= savedSymbolsStoredAsStatic + + result + } + private def transformTemplate(tree: Tree) = { + val Template(parents, self, body) = tree + clearStatics() + val newBody = transformTrees(body) + val templ = treeCopy.Template(tree, parents, self, transformTrees(newStaticMembers.toList) ::: newBody) + try addStaticInits(templ) // postprocess to include static ctors + finally clearStatics() + } private def mkTerm(prefix: String): TermName = unit.freshTermName(prefix) /** Kludge to provide a safe fix for #4560: @@ -60,7 +86,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { } private def typedWithPos(pos: Position)(tree: Tree) = - localTyper typed { atPos(pos)(tree) } + localTyper.typedPos(pos)(tree) /** A value class is defined to be only Java-compatible values: unit is * not part of it, as opposed to isValueClass in definitions. scala.Int is @@ -71,7 +97,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /** The boxed type if it's a primitive; identity otherwise. */ def toBoxedType(tp: Type) = if (isJavaValueType(tp)) boxedClass(tp.typeSymbol).tpe else tp - + override def transform(tree: Tree): Tree = tree match { /* Transforms dynamic calls (i.e. calls to methods that are undefined @@ -116,16 +142,15 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* ### CREATING THE METHOD CACHE ### */ - def addStaticVariableToClass(forName: String, forType: Type, forInit: Tree, isFinal: Boolean): Symbol = { - val varSym = ( - currentClass.newVariable(ad.pos, mkTerm(forName)) - setFlag (PRIVATE | STATIC | SYNTHETIC) - setInfo (forType) + def addStaticVariableToClass(forName: TermName, forType: Type, forInit: Tree, isFinal: Boolean): Symbol = { + 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) @@ -137,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 @@ -168,9 +192,9 @@ abstract class CleanUp extends Transform with ast.TreeDSL { */ val reflParamsCacheSym: Symbol = - addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) + addStaticVariableToClass(nme.reflParamsCacheName, theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) - addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) { + addStaticMethodToClass(nme.reflMethodName, List(ClassClass.tpe), MethodClass.tpe) { case Pair(reflMethodSym, List(forReceiverSym)) => (REF(forReceiverSym) DOT Class_getMethod)(LIT(method), safeREF(reflParamsCacheSym)) } @@ -197,18 +221,18 @@ abstract class CleanUp extends Transform with ast.TreeDSL { */ val reflParamsCacheSym: Symbol = - addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) + addStaticVariableToClass(nme.reflParamsCacheName, theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) val reflMethodCacheSym: Symbol = - addStaticVariableToClass("reflMethod$Cache", MethodClass.tpe, NULL, false) + addStaticVariableToClass(nme.reflMethodCacheName, MethodClass.tpe, NULL, false) val reflClassCacheSym: Symbol = - addStaticVariableToClass("reflClass$Cache", SoftReferenceClass.tpe, NULL, false) + addStaticVariableToClass(nme.reflClassCacheName, SoftReferenceClass.tpe, NULL, false) def isCacheEmpty(receiver: Symbol): Tree = reflClassCacheSym.IS_NULL() OR (reflClassCacheSym.GET() OBJ_NE REF(receiver)) - addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) { + addStaticMethodToClass(nme.reflMethodName, List(ClassClass.tpe), MethodClass.tpe) { case Pair(reflMethodSym, List(forReceiverSym)) => BLOCK( IF (isCacheEmpty(forReceiverSym)) THEN BLOCK( @@ -244,15 +268,17 @@ abstract class CleanUp extends Transform with ast.TreeDSL { */ val reflParamsCacheSym: Symbol = - addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) + addStaticVariableToClass(nme.reflParamsCacheName, theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes), true) def mkNewPolyCache = gen.mkSoftRef(NEW(TypeTree(EmptyMethodCacheClass.tpe))) - val reflPolyCacheSym: Symbol = addStaticVariableToClass("reflPoly$Cache", SoftReferenceClass.tpe, mkNewPolyCache, false) + val reflPolyCacheSym: Symbol = ( + addStaticVariableToClass(nme.reflPolyCacheName, SoftReferenceClass.tpe, mkNewPolyCache, false) + ) def getPolyCache = gen.mkCast(fn(safeREF(reflPolyCacheSym), nme.get), MethodCacheClass.tpe) - addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) + 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, @@ -274,24 +300,13 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* ### HANDLING METHODS NORMALLY COMPILED TO OPERATORS ### */ - // Can't shortcut on BoxedNumber because BoxesRunTime - // is unforgiving of other Numbers showing up. - def testForNumber(qual1: Tree): Tree = ( - (qual1 IS_OBJ BoxedIntClass.tpe) - OR (qual1 IS_OBJ BoxedLongClass.tpe) - OR (qual1 IS_OBJ BoxedDoubleClass.tpe) - OR (qual1 IS_OBJ BoxedFloatClass.tpe) - OR (qual1 IS_OBJ BoxedByteClass.tpe) - OR (qual1 IS_OBJ BoxedShortClass.tpe) - OR (qual1 IS_OBJ BoxedCharacterClass.tpe) - ) - def testForBoolean(qual1: Tree): Tree = ( - (qual1 IS_OBJ BoxedBooleanClass.tpe) - ) - def testForName(name: Name): Tree => Tree = ( - if (nme.CommonOpNames(name)) t => testForNumber(t) OR testForBoolean(t) - else if (nme.BooleanOpNames(name)) testForBoolean - else testForNumber + def testForName(name: Name): Tree => Tree = t => ( + if (nme.CommonOpNames(name)) + gen.mkMethodCall(getMember(BoxesRunTimeClass, nme.isBoxedNumberOrBoolean), t :: Nil) + else if (nme.BooleanOpNames(name)) + t IS_OBJ BoxedBooleanClass.tpe + else + gen.mkMethodCall(getMember(BoxesRunTimeClass, nme.isBoxedNumber), t :: Nil) ) /** The Tree => Tree function in the return is necessary to prevent the original qual @@ -387,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)) @@ -475,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( @@ -525,31 +540,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * constructor. */ case Template(parents, self, body) => localTyper = typer.atOwner(tree, currentClass) - var savedNewStaticMembers : mutable.Buffer[Tree] = null - var savedNewStaticInits : mutable.Buffer[Tree] = null - var savedSymbolsStoredAsStatic : mutable.Map[String, Symbol] = null - if(forMSIL) { - savedNewStaticMembers = newStaticMembers.clone - savedNewStaticInits = newStaticInits.clone - savedSymbolsStoredAsStatic = symbolsStoredAsStatic.clone - } - newStaticMembers.clear - newStaticInits.clear - symbolsStoredAsStatic.clear - val transformedTemplate: Template = { - var newBody = transformTrees(body) - treeCopy.Template(tree, parents, self, transformTrees(newStaticMembers.toList) ::: newBody) - } - val res = addStaticInits(transformedTemplate) // postprocess to include static ctors - newStaticMembers.clear - newStaticInits.clear - symbolsStoredAsStatic.clear - if(forMSIL) { - newStaticMembers ++= savedNewStaticMembers - newStaticInits ++= savedNewStaticInits - symbolsStoredAsStatic ++= savedSymbolsStoredAsStatic - } - res + if (forMSIL) savingStatics( transformTemplate(tree) ) + else transformTemplate(tree) case Literal(c) if (c.tag == ClassTag) && !forMSIL=> val tpe = c.typeValue @@ -571,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) @@ -612,15 +604,12 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * And, finally, be advised - scala symbol literal and the Symbol class of the compiler * have little in common. */ - case symapp @ Apply(Select(Select(a @ Ident(nme.scala_), b @ nme.Symbol), nme.apply), - List(Literal(Constant(symname: String)))) => + case Apply(fn, (arg @ Literal(Constant(symname: String))) :: Nil) if fn.symbol == Symbol_apply => // add the symbol name to a map if it's not there already - val rhs = gen.mkCast(Apply(gen.scalaDot(nme.Symbol), List(Literal(Constant(symname)))), symbolType) - val staticFieldSym = getSymbolStaticField(symapp.pos, symname, rhs, symapp) - + val rhs = gen.mkMethodCall(Symbol_apply, arg :: Nil) + val staticFieldSym = getSymbolStaticField(tree.pos, symname, rhs, tree) // create a reference to a static field - val ntree = typedWithPos(symapp.pos)(safeREF(staticFieldSym)) - + val ntree = typedWithPos(tree.pos)(safeREF(staticFieldSym)) super.transform(ntree) // This transform replaces Array(Predef.wrapArray(Array(...)), <manifest>) @@ -640,19 +629,20 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * If it doesn't exist, i.e. the symbol is encountered the first time, * it creates a new static field definition and initialization and returns it. */ - private def getSymbolStaticField(pos: Position, symname: String, rhs: Tree, tree: Tree): Symbol = + private def getSymbolStaticField(pos: Position, symname: String, rhs: Tree, tree: Tree): Symbol = { symbolsStoredAsStatic.getOrElseUpdate(symname, { val theTyper = typer.atOwner(tree, currentClass) // create a symbol for the static field - val stfieldSym = currentClass.newVariable(pos, mkTerm("symbol$")) - .setFlag(PRIVATE | STATIC | SYNTHETIC | FINAL) - .setInfo(symbolType) + val stfieldSym = ( + currentClass.newVariable(mkTerm("symbol$"), pos, PRIVATE | STATIC | SYNTHETIC | FINAL) + setInfo SymbolClass.tpe + ) currentClass.info.decls enter stfieldSym // create field definition and initialization - val stfieldDef = theTyper.typed { atPos(pos)(VAL(stfieldSym) === rhs) } - val stfieldInit = theTyper.typed { atPos(pos)(safeREF(stfieldSym) === rhs) } + val stfieldDef = theTyper.typedPos(pos)(VAL(stfieldSym) === rhs) + val stfieldInit = theTyper.typedPos(pos)(safeREF(stfieldSym) === rhs) // add field definition to new defs newStaticMembers append stfieldDef @@ -660,6 +650,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { stfieldSym }) + } /* finds the static ctor DefDef tree within the template if it exists. */ private def findStaticCtor(template: Template): Option[Tree] = @@ -671,7 +662,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* changes the template for the class so that it contains a static constructor with symbol fields inits, * augments an existing static ctor if one already existed. */ - private def addStaticInits(template: Template): Template = + private def addStaticInits(template: Template): Template = { if (newStaticInits.isEmpty) template else { @@ -693,11 +684,12 @@ abstract class CleanUp extends Transform with ast.TreeDSL { // create new static ctor val staticCtorSym = currentClass.newStaticConstructor(template.pos) val rhs = Block(newStaticInits.toList, Literal(Constant())) - val staticCtorTree = DefDef(staticCtorSym, rhs) - localTyper.typed { atPos(template.pos)(staticCtorTree) } + + localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs)) } treeCopy.Template(template, template.parents, template.self, newCtor :: template.body) } + } } // CleanUpTransformer 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 b327579c8b..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 @@ -887,8 +885,9 @@ abstract class Erasure extends AddInterfaces fun.symbol != Object_isInstanceOf) => // leave all other type tests/type casts, remove all other type applications preErase(fun) - case Apply(fn @ Select(qual, name), args) if (fn.symbol.owner == ArrayClass) => - if (unboundedGenericArrayLevel(qual.tpe.widen) == 1) + case Apply(fn @ Select(qual, name), args) if fn.symbol.owner == ArrayClass => + // Have to also catch calls to abstract types which are bounded by Array. + if (unboundedGenericArrayLevel(qual.tpe.widen) == 1 || qual.tpe.typeSymbol.isAbstractType) { // convert calls to apply/update/length on generic arrays to // calls of ScalaRunTime.array_xxx method calls global.typer.typedPos(tree.pos)({ @@ -901,14 +900,15 @@ abstract class Erasure extends AddInterfaces } gen.mkRuntimeCall(arrayMethodName, qual :: args) }) - else + } + else { // store exact array erasure in map to be retrieved later when we might // need to do the cast in adaptMember treeCopy.Apply( tree, SelectFromArray(qual, name, erasure(tree.symbol, qual.tpe)).copyAttrs(fn), args) - + } case Apply(fn @ Select(qual, _), Nil) if interceptedMethods(fn.symbol) => if (fn.symbol == Any_## || fn.symbol == Object_##) { // This is unattractive, but without it we crash here on ().## because after 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..0f11161914 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -213,17 +213,14 @@ abstract class LambdaLift extends InfoTransform { 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 +406,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..f199195b81 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 @@ -207,6 +199,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..53e88b33c8 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) @@ -191,12 +192,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 +394,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 +612,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 +634,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 +661,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 +783,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 2bd307e31a..b1612f24ef 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 " + @@ -1447,8 +1420,17 @@ trait Infer { /** A traverser to collect type parameters referred to in a type */ object freeTypeParamsOfTerms extends SymCollector { - protected def includeCondition(sym: Symbol): Boolean = - sym.isAbstractType && sym.owner.isTerm + // An inferred type which corresponds to an unknown type + // constructor creates a file/declaration order-dependent crasher + // situation, the behavior of which depends on the state at the + // time the typevar is created. Until we can deal with these + // properly, we can avoid it by ignoring type parameters which + // have type constructors amongst their bounds. See SI-4070. + protected def includeCondition(sym: Symbol) = ( + sym.isAbstractType + && sym.owner.isTerm + && !sym.info.bounds.exists(_.typeParams.nonEmpty) + ) } /** A traverser to collect type parameters referred to in a type 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..354b8caaa3 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) } @@ -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..4104803194 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 @@ -1245,7 +1245,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 +1377,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..884ad7af3d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1659,7 +1659,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 +1793,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 +1814,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 +2529,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 +2542,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 +2817,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) } @@ -3079,7 +3079,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 +3120,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 +3130,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") @@ -3804,7 +3804,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { 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 @@ -4098,8 +4115,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) => 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/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/StringContext.scala b/src/library/scala/StringContext.scala new file mode 100644 index 0000000000..1f0b4c766e --- /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/Symbol.scala b/src/library/scala/Symbol.scala index 8a17ae87b0..8851f1ab91 100644 --- a/src/library/scala/Symbol.scala +++ b/src/library/scala/Symbol.scala @@ -31,8 +31,8 @@ final class Symbol private (val name: String) extends Serializable { override def equals(other: Any) = this eq other.asInstanceOf[AnyRef] } -object Symbol extends UniquenessCache[String, Symbol] -{ +object Symbol extends UniquenessCache[String, Symbol] { + override def apply(name: String): Symbol = super.apply(name) protected def valueFromKey(name: String): Symbol = new Symbol(name) protected def keyFromValue(sym: Symbol): Option[String] = Some(sym.name) } 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..b4813e6341 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -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/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/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/ClassManifest.scala b/src/library/scala/reflect/ClassManifest.scala index acd28f04f5..466b57dea7 100644 --- a/src/library/scala/reflect/ClassManifest.scala +++ b/src/library/scala/reflect/ClassManifest.scala @@ -127,7 +127,7 @@ trait ClassManifest[T] extends OptManifest[T] with Equals with Serializable { java.lang.reflect.Array.newInstance(tp, 0).getClass.asInstanceOf[jClass[Array[T]]] def arrayManifest: ClassManifest[Array[T]] = - ClassManifest.classType[Array[T]](arrayClass[T](erasure)) + ClassManifest.classType[Array[T]](arrayClass[T](erasure), this) def newArray(len: Int): Array[T] = java.lang.reflect.Array.newInstance(erasure, len).asInstanceOf[Array[T]] @@ -220,7 +220,7 @@ object ClassManifest { new ClassTypeManifest[T](Some(prefix), clazz, args.toList) def arrayType[T](arg: OptManifest[_]): ClassManifest[Array[T]] = arg match { - case NoManifest => Object.asInstanceOf[ClassManifest[Array[T]]] + case NoManifest => Object.asInstanceOf[ClassManifest[Array[T]]] case m: ClassManifest[_] => m.asInstanceOf[ClassManifest[T]].arrayManifest } diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index 18fd34ed2e..8bd45c0e33 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -44,7 +44,7 @@ trait Manifest[T] extends ClassManifest[T] with Equals { override def typeArguments: List[Manifest[_]] = Nil override def arrayManifest: Manifest[Array[T]] = - Manifest.classType[Array[T]](arrayClass[T](erasure)) + Manifest.classType[Array[T]](arrayClass[T](erasure), this) override def canEqual(that: Any): Boolean = that match { case _: Manifest[_] => true @@ -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/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/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala index f48d99f5af..cbe778f09b 100644 --- a/src/library/scala/runtime/AbstractPartialFunction.scala +++ b/src/library/scala/runtime/AbstractPartialFunction.scala @@ -26,7 +26,7 @@ abstract class AbstractPartialFunction[-T1, +R] private var fallBackField: PartialFunction[T1 @uncheckedVariance, R @uncheckedVariance] = _ def fallBack: PartialFunction[T1, R] = synchronized { - if (fallBackField == null) fallBackField = PartialFunction.empty + if (fallBackField eq null) fallBackField = PartialFunction.empty fallBackField } @@ -38,7 +38,7 @@ abstract class AbstractPartialFunction[-T1, +R] override def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = { val result = this.clone.asInstanceOf[AbstractPartialFunction[A1, B1]] result.synchronized { - result.fallBackField = this.fallBackField orElse that + result.fallBackField = if (this.fallBackField eq null) that else this.fallBackField orElse that result } } diff --git a/src/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java index c726c56d0e..b19c8d086c 100644 --- a/src/library/scala/runtime/BoxesRunTime.java +++ b/src/library/scala/runtime/BoxesRunTime.java @@ -769,6 +769,24 @@ public final class BoxesRunTime } throw new NoSuchMethodException(); } + + public static boolean isBoxedNumberOrBoolean(Object arg) { + if (arg instanceof java.lang.Boolean) + return true; + else + return isBoxedNumber(arg); + } + public static boolean isBoxedNumber(Object arg) { + return ( + (arg instanceof java.lang.Integer) + || (arg instanceof java.lang.Long) + || (arg instanceof java.lang.Double) + || (arg instanceof java.lang.Float) + || (arg instanceof java.lang.Short) + || (arg instanceof java.lang.Character) + || (arg instanceof java.lang.Byte) + ); + } /** arg.toChar */ public static java.lang.Character toCharacter(Object arg) throws NoSuchMethodException { diff --git a/src/library/scala/xml/Elem.scala b/src/library/scala/xml/Elem.scala index 127e6e0ab7..df52b34f87 100644 --- a/src/library/scala/xml/Elem.scala +++ b/src/library/scala/xml/Elem.scala @@ -41,7 +41,7 @@ object Elem { class Elem( override val prefix: String, val label: String, - override val attributes: MetaData, + attributes1: MetaData, override val scope: NamespaceBinding, val child: Node*) extends Node with Serializable @@ -49,6 +49,8 @@ extends Node with Serializable final override def doCollectNamespaces = true final override def doTransform = true + override val attributes = MetaData.normalize(attributes1, scope) + if (prefix == "") throw new IllegalArgumentException("prefix of zero length, use null instead") diff --git a/src/library/scala/xml/MetaData.scala b/src/library/scala/xml/MetaData.scala index 98e863eb37..c516747bae 100644 --- a/src/library/scala/xml/MetaData.scala +++ b/src/library/scala/xml/MetaData.scala @@ -38,8 +38,8 @@ object MetaData { def iterate(md: MetaData, normalized_attribs: MetaData, set: Set[String]): MetaData = { lazy val key = getUniversalKey(md, scope) if (md eq Null) normalized_attribs - else if (set(key)) iterate(md.next, normalized_attribs, set) - else iterate(md.next, md copy normalized_attribs, set + key) + else if ((md.value eq null) || set(key)) iterate(md.next, normalized_attribs, set) + else md copy iterate(md.next, normalized_attribs, set + key) } iterate(attribs, Null, Set()) } diff --git a/src/library/scala/xml/PrefixedAttribute.scala b/src/library/scala/xml/PrefixedAttribute.scala index 436dfcda43..b80d6a1c73 100644 --- a/src/library/scala/xml/PrefixedAttribute.scala +++ b/src/library/scala/xml/PrefixedAttribute.scala @@ -13,22 +13,25 @@ package scala.xml * * @param pre ... * @param key ... - * @param value the attribute value, which may not be null + * @param value the attribute value * @param next ... */ class PrefixedAttribute( val pre: String, val key: String, val value: Seq[Node], - val next: MetaData) + val next1: MetaData) extends Attribute { - if (value eq null) - throw new UnsupportedOperationException("value is null") + val next = if (value ne null) next1 else next1.remove(key) - /** same as this(key, Utility.parseAttributeValue(value), next) */ + /** same as this(pre, key, Text(value), next), or no attribute if value is null */ def this(pre: String, key: String, value: String, next: MetaData) = - this(pre, key, Text(value), next) + this(pre, key, if (value ne null) Text(value) else null: NodeSeq, next) + + /** same as this(pre, key, value.get, next), or no attribute if value is None */ + def this(pre: String, key: String, value: Option[Seq[Node]], next: MetaData) = + this(pre, key, value.orNull, next) /** Returns a copy of this unprefixed attribute with the given * next field. diff --git a/src/library/scala/xml/UnprefixedAttribute.scala b/src/library/scala/xml/UnprefixedAttribute.scala index c56fba1e6c..b6800d5ed1 100644 --- a/src/library/scala/xml/UnprefixedAttribute.scala +++ b/src/library/scala/xml/UnprefixedAttribute.scala @@ -22,7 +22,7 @@ extends Attribute final val pre = null val next = if (value ne null) next1 else next1.remove(key) - /** same as this(key, Text(value), next) */ + /** same as this(key, Text(value), next), or no attribute if value is null */ def this(key: String, value: String, next: MetaData) = this(key, if (value ne null) Text(value) else null: NodeSeq, next) diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index 9b48f4e1bb..fc20b892b9 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -61,7 +61,7 @@ object Utility extends AnyRef with parsing.TokenTests { val key = md.key val smaller = sort(md.filter { m => m.key < key }) val greater = sort(md.filter { m => m.key > key }) - smaller.append( Null ).append(md.copy ( greater )) + smaller.copy(md.copy ( greater )) } /** Return the node with its attribute list sorted alphabetically 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/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/SBTRunner.scala b/src/partest/scala/tools/partest/nest/SBTRunner.scala index ae54e51761..0c176e4b06 100644 --- a/src/partest/scala/tools/partest/nest/SBTRunner.scala +++ b/src/partest/scala/tools/partest/nest/SBTRunner.scala @@ -71,11 +71,10 @@ 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/test/benchmarking/AVL-insert-random.scala b/test/benchmarking/AVL-insert-random.scala new file mode 100644 index 0000000000..7299e330f5 --- /dev/null +++ b/test/benchmarking/AVL-insert-random.scala @@ -0,0 +1,67 @@ +package scala.collection + + + + + +class Dummy(val a: Int) extends math.Ordered[Dummy] { + def compare(other: Dummy) = this.a - other.a + override def toString = a.toString +} + + +object RandomGlobal { + val sz = 500000 + val data = util.Random.shuffle((0 until sz) map { new Dummy(_) }) toArray; +} + + +import RandomGlobal._ + + +object RandomAVL extends testing.Benchmark { + + def run() { + val avl = new collection.mutable.TreeSet[Dummy] + + var i = 0 + while (i < sz) { + val elem = data(i) + avl += elem + i += 1 + } + } + +} + + +object RandomImmutableTreeSet extends testing.Benchmark { + + def run() { + var tree = new collection.immutable.TreeSet[Dummy] + + var i = 0 + while (i < sz) { + val elem = data(i) + tree += elem + i += 1 + } + } + +} + + +object RandomJavaTreeSet extends testing.Benchmark { + + def run() { + val tree = new java.util.TreeSet[Dummy] + + var i = 0 + while (i < sz) { + val elem = data(i) + tree add elem + i += 1 + } + } + +} diff --git a/test/benchmarking/AVL-insert.scala b/test/benchmarking/AVL-insert.scala new file mode 100644 index 0000000000..4f3ab390c9 --- /dev/null +++ b/test/benchmarking/AVL-insert.scala @@ -0,0 +1,67 @@ +package scala.collection + + + + + +class Dummy(val a: Int) extends math.Ordered[Dummy] { + def compare(other: Dummy) = this.a - other.a + override def toString = a.toString +} + + +object Global { + val sz = 500000 + val data = (0 until sz) map { new Dummy(_) } toArray +} + + +import Global._ + + +object AVL extends testing.Benchmark { + + def run() { + val avl = new collection.mutable.TreeSet[Dummy] + + var i = 0 + while (i < sz) { + val elem = data(i) + avl += elem + i += 1 + } + } + +} + + +object ImmutableTreeSet extends testing.Benchmark { + + def run() { + var tree = new collection.immutable.TreeSet[Dummy] + + var i = 0 + while (i < sz) { + val elem = data(i) + tree += elem + i += 1 + } + } + +} + + +object JavaTreeSet extends testing.Benchmark { + + def run() { + val tree = new java.util.TreeSet[Dummy] + + var i = 0 + while (i < sz) { + val elem = data(i) + tree add elem + i += 1 + } + } + +} diff --git a/test/files/jvm/serialization.check b/test/files/jvm/serialization.check index 15708f0c3b..f58f763a76 100644 --- a/test/files/jvm/serialization.check +++ b/test/files/jvm/serialization.check @@ -188,6 +188,10 @@ x = WrappedArray(1, 2, 3) y = WrappedArray(1, 2, 3) x equals y: true, y equals x: true +x = TreeSet(1, 2, 3) +y = TreeSet(1, 2, 3) +x equals y: true, y equals x: true + x = xml:src="hello" y = xml:src="hello" x equals y: true, y equals x: true @@ -202,7 +206,7 @@ x equals y: true, y equals x: true x = <html> <body> - <table cellspacing="0" cellpadding="2"> + <table cellpadding="2" cellspacing="0"> <tr> <th>Last Name</th> <th>First Name</th> @@ -222,7 +226,7 @@ x = <html> </html> y = <html> <body> - <table cellspacing="0" cellpadding="2"> + <table cellpadding="2" cellspacing="0"> <tr> <th>Last Name</th> <th>First Name</th> diff --git a/test/files/jvm/serialization.scala b/test/files/jvm/serialization.scala index 9391b60e46..73bed2d46b 100644 --- a/test/files/jvm/serialization.scala +++ b/test/files/jvm/serialization.scala @@ -286,7 +286,7 @@ object Test3_mutable { import scala.collection.mutable.{ ArrayBuffer, ArrayBuilder, ArraySeq, ArrayStack, BitSet, DoubleLinkedList, HashMap, HashSet, History, LinkedList, ListBuffer, Publisher, Queue, - Stack, StringBuilder, WrappedArray} + Stack, StringBuilder, WrappedArray, TreeSet} // in alphabetic order try { @@ -380,6 +380,11 @@ object Test3_mutable { val wa1 = WrappedArray.make(Array(1, 2, 3)) val _wa1: WrappedArray[Int] = read(write(wa1)) check(wa1, _wa1) + + // TreeSet + val ts1 = TreeSet[Int]() ++= Array(1, 2, 3) + val _ts1: TreeSet[Int] = read(write(ts1)) + check(ts1, _ts1) } catch { case e: Exception => diff --git a/test/files/jvm/xml03syntax.check b/test/files/jvm/xml03syntax.check index 75dc539137..9fbedc2ae6 100644 --- a/test/files/jvm/xml03syntax.check +++ b/test/files/jvm/xml03syntax.check @@ -23,4 +23,4 @@ true 4 node=<elem key="<b>hello</b>"></elem>, key=Some(<b>hello</b>) -node=<elem ></elem>, key=None +node=<elem></elem>, key=None diff --git a/test/files/neg/cyclics-import.check b/test/files/neg/cyclics-import.check new file mode 100644 index 0000000000..ef355fab0a --- /dev/null +++ b/test/files/neg/cyclics-import.check @@ -0,0 +1,15 @@ +cyclics-import.scala:1: error: encountered unrecoverable cycle resolving import. +Note: this is often due in part to a class depending on a definition nested within its companion. +If applicable, you may wish to try moving some members into another object. +import User.UserStatus._ + ^ +cyclics-import.scala:12: error: not found: type Value + type UserStatus = Value + ^ +cyclics-import.scala:14: error: not found: value Value + val Active = Value("1") + ^ +cyclics-import.scala:15: error: not found: value Value + val Disabled = Value("2") + ^ +four errors found diff --git a/test/files/neg/cyclics-import.scala b/test/files/neg/cyclics-import.scala new file mode 100644 index 0000000000..7b510b58e2 --- /dev/null +++ b/test/files/neg/cyclics-import.scala @@ -0,0 +1,17 @@ +import User.UserStatus._ + +class User { + var id: Int = 0 + var email: String = null + var password: String = null + var userStatus: UserStatus = null +} + +object User { + object UserStatus extends Enumeration { + type UserStatus = Value + + val Active = Value("1") + val Disabled = Value("2") + } +} diff --git a/test/files/neg/main1.check b/test/files/neg/main1.check index 734c78e54d..1a7a13e1e9 100644 --- a/test/files/neg/main1.check +++ b/test/files/neg/main1.check @@ -1,25 +1,25 @@ -main1.scala:3: error: Foo has a main method, but foo1.Foo will not be a runnable program. - Its companion is a trait, which means no static forwarder can be generated. +main1.scala:3: error: Foo has a main method with parameter type Array[String], but foo1.Foo will not be a runnable program. + Reason: companion is a trait, which means no static forwarder can be generated. object Foo { // companion is trait ^ -main1.scala:10: error: Foo has a main method, but foo2.Foo will not be a runnable program. - Its companion contains its own main method, which means no static forwarder can be generated. +main1.scala:10: error: Foo has a main method with parameter type Array[String], but foo2.Foo will not be a runnable program. + Reason: companion contains its own main method, which means no static forwarder can be generated. object Foo { // companion has its own main ^ -main1.scala:22: error: Foo has a main method, but foo3.Foo will not be a runnable program. - Its companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. +main1.scala:22: error: Foo has a main method with parameter type Array[String], but foo3.Foo will not be a runnable program. + Reason: companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. object Foo { // Companion contains main, but not an interfering main. ^ -main1.scala:31: error: Foo has a main method, but foo4.Foo will not be a runnable program. - Its companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. +main1.scala:31: error: Foo has a main method with parameter type Array[String], but foo4.Foo will not be a runnable program. + Reason: companion contains its own main method, which means no static forwarder can be generated. object Foo extends Foo { // Inherits main from the class ^ -main1.scala:39: error: Foo has a main method, but foo5.Foo will not be a runnable program. - Its companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. +main1.scala:39: error: Foo has a main method with parameter type Array[String], but foo5.Foo will not be a runnable program. + Reason: companion contains its own main method, which means no static forwarder can be generated. object Foo extends Foo { // Overrides main from the class ^ diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index 01ef54e0ea..01bbe2de4e 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -83,7 +83,7 @@ names-defaults-neg.scala:76: error: no type parameters for method test4: (x: T[T --- because --- argument expression's type is not compatible with formal parameter type; found : List[Int] - required: ?T[?T[List[?T[X forSome { type X }]]]] + required: ?T Error occurred in an application involving default arguments. test4() ^ diff --git a/test/files/neg/nested-fn-print.check b/test/files/neg/nested-fn-print.check new file mode 100644 index 0000000000..ea278554d4 --- /dev/null +++ b/test/files/neg/nested-fn-print.check @@ -0,0 +1,20 @@ +nested-fn-print.scala:4: error: only classes can have declared but undefined members +(Note that variables need to be initialized to be defined) + var x3: Int => Double + ^ +nested-fn-print.scala:7: error: type mismatch; + found : String("a") + required: Int => (Float => Double) + x1 = "a" + ^ +nested-fn-print.scala:8: error: type mismatch; + found : String("b") + required: (Int => Float) => Double + x2 = "b" + ^ +nested-fn-print.scala:9: error: type mismatch; + found : String("c") + required: Int => Double + x3 = "c" + ^ +four errors found diff --git a/test/files/neg/nested-fn-print.scala b/test/files/neg/nested-fn-print.scala new file mode 100644 index 0000000000..9a4bd162c0 --- /dev/null +++ b/test/files/neg/nested-fn-print.scala @@ -0,0 +1,11 @@ +object Test { + var x1: Int => Float => Double = _ + var x2: (Int => Float) => Double = _ + var x3: Int => Double + + def main(args: Array[String]): Unit = { + x1 = "a" + x2 = "b" + x3 = "c" + } +} diff --git a/test/files/neg/specification-scopes.check b/test/files/neg/specification-scopes.check new file mode 100644 index 0000000000..7af9842379 --- /dev/null +++ b/test/files/neg/specification-scopes.check @@ -0,0 +1,12 @@ +P_2.scala:14: error: reference to x is ambiguous; +it is both defined in object C and imported subsequently by +import Q.X._ + println("L14: "+x) // reference to 'x' is ambiguous here + ^ +P_2.scala:19: error: reference to y is ambiguous; +it is imported twice in the same scope by +import P.X._ +and import X.y + println("L19: "+y) // reference to 'y' is ambiguous here + ^ +two errors found diff --git a/test/files/neg/specification-scopes/P_1.scala b/test/files/neg/specification-scopes/P_1.scala new file mode 100644 index 0000000000..3b11f1167d --- /dev/null +++ b/test/files/neg/specification-scopes/P_1.scala @@ -0,0 +1,6 @@ +package P { + object X { val x = 1; val y = 2; } +} +package Q { + object X { val x = true; val y = "" } +} diff --git a/test/files/neg/specification-scopes/P_2.scala b/test/files/neg/specification-scopes/P_2.scala new file mode 100644 index 0000000000..d59f82e90d --- /dev/null +++ b/test/files/neg/specification-scopes/P_2.scala @@ -0,0 +1,21 @@ +package P { // 'X' bound by package clause + import Console._ // 'println' bound by wildcard import + object A { + println("L4: "+X) // 'X' refers to 'P.X' here + object B { + import Q._ // 'X' bound by wildcard import + println("L7: "+X) // 'X' refers to 'Q.X' here + import X._ // 'x' and 'y' bound by wildcard import + println("L8: "+x) // 'x' refers to 'Q.X.x' here + object C { + val x = 3 // 'x' bound by local definition + println("L12: "+x); // 'x' refers to constant '3' here + { import Q.X._ // 'x' and 'y' bound by wildcard + println("L14: "+x) // reference to 'x' is ambiguous here + import X.y // 'y' bound by explicit import + println("L16: "+y); // 'y' refers to 'Q.X.y' here + { val x = "abc" // 'x' bound by local definition + import P.X._ // 'x' and 'y' bound by wildcard + println("L19: "+y) // reference to 'y' is ambiguous here + println("L20: "+x) // 'x' refers to string ''abc'' here +}}}}}} diff --git a/test/files/neg/t0003.check b/test/files/neg/t0003.check index 1913dde9dd..8bab55db3f 100644 --- a/test/files/neg/t0003.check +++ b/test/files/neg/t0003.check @@ -1,5 +1,5 @@ t0003.scala:2: error: type mismatch; - found : A => B => B + found : A => (B => B) required: A => B def foo[A, B, C](l: List[A], f: A => B=>B, g: B=>B=>C): List[C] = l map (g compose f) ^ diff --git a/test/files/neg/t1845.check b/test/files/neg/t1845.check index 7c0bddbc20..a6c82f5659 100644 --- a/test/files/neg/t1845.check +++ b/test/files/neg/t1845.check @@ -1,4 +1,6 @@ -t1845.scala:9: error: illegal cyclic reference involving value <import> - val lexical = new StdLexical - ^ +t1845.scala:6: error: encountered unrecoverable cycle resolving import. +Note: this is often due in part to a class depending on a definition nested within its companion. +If applicable, you may wish to try moving some members into another object. + import lexical._ + ^ one error found diff --git a/test/files/neg/t2870.check b/test/files/neg/t2870.check index 72bc0d98a1..ab962d48c8 100644 --- a/test/files/neg/t2870.check +++ b/test/files/neg/t2870.check @@ -1,7 +1,9 @@ t2870.scala:1: error: not found: type Jar (similar: Jars) class Jars(jar: Jar) ^ -t2870.scala:6: error: illegal cyclic reference involving value <import> - val scala = fromClasspathString(javaClassPath) - ^ +t2870.scala:4: error: encountered unrecoverable cycle resolving import. +Note: this is often due in part to a class depending on a definition nested within its companion. +If applicable, you may wish to try moving some members into another object. + import scala.util.Properties.javaClassPath + ^ two errors found diff --git a/test/files/neg/t3240.check b/test/files/neg/t3240.check index 7ebabd5fcd..efae682c66 100644 --- a/test/files/neg/t3240.check +++ b/test/files/neg/t3240.check @@ -1,7 +1,4 @@ t3240.scala:3: error: only classes can have declared but undefined members type t ^ -t3240.scala:5: error: type arguments [this.t] do not conform to method asInstanceOf's type parameter bounds [T0] - a.getOrElse(defVal).asInstanceOf[t] - ^ -two errors found +one error found diff --git a/test/files/neg/t4749.check b/test/files/neg/t4749.check new file mode 100644 index 0000000000..93ad3935fa --- /dev/null +++ b/test/files/neg/t4749.check @@ -0,0 +1,28 @@ +t4749.scala:2: error: Fail1 has a main method with parameter type Array[String], but bippy.Fail1 will not be a runnable program. + Reason: main method must have exact signature (Array[String])Unit + object Fail1 { + ^ +t4749.scala:6: error: Fail2 has a main method with parameter type Array[String], but bippy.Fail2 will not be a runnable program. + Reason: main methods cannot be generic. + object Fail2 { + ^ +t4749.scala:13: error: Fail3 has a main method with parameter type Array[String], but bippy.Fail3 will not be a runnable program. + Reason: main methods cannot refer to type parameters or abstract types. + object Fail3 extends Bippy[Unit] { } + ^ +t4749.scala:16: error: Fail4 has a main method with parameter type Array[String], but bippy.Fail4 will not be a runnable program. + Reason: companion is a trait, which means no static forwarder can be generated. + + object Fail4 { + ^ +t4749.scala:21: error: Fail5 has a main method with parameter type Array[String], but bippy.Fail5 will not be a runnable program. + Reason: companion contains its own main method, which means no static forwarder can be generated. + + object Fail5 extends Fail5 { } + ^ +t4749.scala:26: error: Fail6 has a main method with parameter type Array[String], but bippy.Fail6 will not be a runnable program. + Reason: companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. + + object Fail6 { + ^ +6 errors found diff --git a/test/files/neg/t4749.flags b/test/files/neg/t4749.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t4749.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/neg/t4749.scala b/test/files/neg/t4749.scala new file mode 100644 index 0000000000..0973c36097 --- /dev/null +++ b/test/files/neg/t4749.scala @@ -0,0 +1,44 @@ +package bippy { + object Fail1 { + def main(args: Array[String]): Any = () + } + + object Fail2 { + def main[T](args: Array[String]): T = null.asInstanceOf[T] + } + + abstract class Bippy[T] { + def main(args: Array[String]): T = null.asInstanceOf[T] + } + object Fail3 extends Bippy[Unit] { } + + + object Fail4 { + def main(args: Array[String]): Unit = () + } + trait Fail4 { } + + object Fail5 extends Fail5 { } + class Fail5 { + def main(args: Array[String]): Unit = () + } + + object Fail6 { + def main(args: Array[String]): Unit = () + } + class Fail6 { + def main = "bippy" + } + + object Win1 { + def main(args: Array[String]): Unit = () + } + object Win2 extends Bippy[Unit] { + override def main(args: Array[String]): Unit = () + } + trait WinBippy[T] { + def main(args: Array[String]): T = null.asInstanceOf[T] + } + object Win3 extends WinBippy[Unit] { } +} + diff --git a/test/files/neg/t692.check b/test/files/neg/t692.check index 12b7d40ba5..4149366309 100644 --- a/test/files/neg/t692.check +++ b/test/files/neg/t692.check @@ -13,12 +13,7 @@ t692.scala:13: error: class Foo takes type parameters t692.scala:14: error: class Foo takes type parameters implicit def typeOfBar[T4 <: Foo](implicit elem : RefType[T4]) : RefType[Bar[T4]] = ^ -t692.scala:15: error: type mismatch; - found : test3.this.BarType[T4] - required: test3.this.RefType[test3.this.Bar[T4]] - BarType(elem); - ^ t692.scala:19: error: class Foo takes type parameters class Bar[A <: Foo](implicit tpeA : Type[A]) extends Foo; ^ -7 errors found +6 errors found diff --git a/test/files/pos/package-implicit/ActorRef.scala b/test/files/pos/package-implicit/ActorRef.scala new file mode 100644 index 0000000000..e3f93c5e72 --- /dev/null +++ b/test/files/pos/package-implicit/ActorRef.scala @@ -0,0 +1,7 @@ +package t1000647.foo + +trait ActorRef { + def stop(): Unit = {} +} + +trait ScalaActorRef { self: ActorRef => }
\ No newline at end of file diff --git a/test/files/pos/package-implicit/DataFlow.scala b/test/files/pos/package-implicit/DataFlow.scala new file mode 100644 index 0000000000..d948280d0d --- /dev/null +++ b/test/files/pos/package-implicit/DataFlow.scala @@ -0,0 +1,7 @@ +package t1000647.bar + +import t1000647.foo.{ScalaActorRef} + +object DataFlow { + def foo(ref: ScalaActorRef) = ref.stop() +} diff --git a/test/files/pos/package-implicit/package.scala b/test/files/pos/package-implicit/package.scala new file mode 100644 index 0000000000..96c4b133f8 --- /dev/null +++ b/test/files/pos/package-implicit/package.scala @@ -0,0 +1,6 @@ +package t1000647 + +package object foo { + implicit def scala2ActorRef(ref: ScalaActorRef): ActorRef = + ref.asInstanceOf[ActorRef] +}
\ No newline at end of file diff --git a/test/files/pos/raw-map/J_1.java b/test/files/pos/raw-map/J_1.java new file mode 100644 index 0000000000..bd43bcac81 --- /dev/null +++ b/test/files/pos/raw-map/J_1.java @@ -0,0 +1,4 @@ +public class J_1 { + public void setRawType(java.util.Map x) { + } +} diff --git a/test/files/pos/raw-map/S_2.scala b/test/files/pos/raw-map/S_2.scala new file mode 100644 index 0000000000..de6c4ee5c2 --- /dev/null +++ b/test/files/pos/raw-map/S_2.scala @@ -0,0 +1,6 @@ +class Foo { + def foo { + val x: J_1 = null + x.setRawType(new java.util.HashMap) + } +} diff --git a/test/files/pos/t3999/a_1.scala b/test/files/pos/t3999/a_1.scala new file mode 100644 index 0000000000..25366ee9c4 --- /dev/null +++ b/test/files/pos/t3999/a_1.scala @@ -0,0 +1,9 @@ +package foo + +class Outside + +package object bar { + class Val(b: Boolean) + implicit def boolean2Val(b: Boolean) = new Val(b) + implicit def boolean2Outside(b: Boolean) = new Outside +}
\ No newline at end of file diff --git a/test/files/pos/t3999/b_2.scala b/test/files/pos/t3999/b_2.scala new file mode 100644 index 0000000000..1af82c8c5b --- /dev/null +++ b/test/files/pos/t3999/b_2.scala @@ -0,0 +1,7 @@ +package foo +package bar + +class A { + val s: Val = false + val o: Outside = false +}
\ No newline at end of file diff --git a/test/files/pos/t4070.scala b/test/files/pos/t4070.scala new file mode 100644 index 0000000000..29c8d16e30 --- /dev/null +++ b/test/files/pos/t4070.scala @@ -0,0 +1,37 @@ +package a { + // method before classes + trait Foo { + def crash(x: Dingus[_]): Unit = x match { case m: Bippy[tv] => () } + + class Dingus[T] + class Bippy[CC[X] <: Seq[X]]() extends Dingus[CC[Int]] + } +} + +package b { + // classes before method + trait Foo { + class Dingus[T] + class Bippy[CC[X] <: Seq[X]]() extends Dingus[CC[Int]] + + def crash(x: Dingus[_]): Unit = x match { case m: Bippy[tv] => () } + } +} + + +/* +// With crash below the clasess: +% scalac -Dscalac.debug.tvar ./a.scala +[ create] ?_$1 ( In Foo#crash ) +[ setInst] tv[Int] ( In Foo#crash, _$1=tv[Int] ) +[ create] tv[Int] ( In Foo#crash ) +[ clone] tv[Int] ( Foo#crash ) + +// With crash above the classes: +% scalac -Dscalac.debug.tvar ./a.scala +[ create] ?tv ( In Foo#crash ) +./a.scala:2: error: Invalid type application in TypeVar: List(), List(Int) + def crash(x: Dingus[_]): Unit = x match { case m: Bippy[tv] => () } + ^ +one error found +*/ diff --git a/test/files/pos/t4070b.scala b/test/files/pos/t4070b.scala new file mode 100644 index 0000000000..36d03de80c --- /dev/null +++ b/test/files/pos/t4070b.scala @@ -0,0 +1,35 @@ +package a { + abstract class DeliteOp[B] + abstract class DeliteCollection[A] + abstract class Exp[T] { def Type: T } + + trait DeliteOpMap[A,B,C[X] <: DeliteCollection[X]] extends DeliteOp[C[B]] { + val in: Exp[C[A]] + val func: Exp[B] + val alloc: Exp[C[B]] + } + + object Test { + def f(x: DeliteOp[_]) = x match { + case map: DeliteOpMap[_,_,_] => map.alloc.Type + } + } +} + +package b { + object Test { + def f(x: DeliteOp[_]) = x match { + case map: DeliteOpMap[_,_,_] => map.alloc.Type + } + } + + abstract class DeliteOp[B] + abstract class DeliteCollection[A] + abstract class Exp[T] { def Type: T } + + trait DeliteOpMap[A,B,C[X] <: DeliteCollection[X]] extends DeliteOp[C[B]] { + val in: Exp[C[A]] + val func: Exp[B] + val alloc: Exp[C[B]] + } +}
\ No newline at end of file diff --git a/test/files/pos/t4869.scala b/test/files/pos/t4869.scala new file mode 100644 index 0000000000..f84aa4ed07 --- /dev/null +++ b/test/files/pos/t4869.scala @@ -0,0 +1,8 @@ +// /scala/trac/4869/a.scala +// Wed Jan 4 21:17:29 PST 2012 + +class C[T] +class A { + def f[T](x: T): C[_ <: T] = null + def g = List(1d) map f +} diff --git a/test/files/pos/t5020.scala b/test/files/pos/t5020.scala new file mode 100644 index 0000000000..06f7723f9f --- /dev/null +++ b/test/files/pos/t5020.scala @@ -0,0 +1,19 @@ +package a { + sealed trait GenericList[U, M[_ <: U]] { + type Transformed[N[MMA <: U]] <: GenericList[U, N] + } + + trait GenericCons[U, M[_ <: U], T <: GenericList[U, M]] extends GenericList[U, M] { + type Transformed[N[MMB <: U]] = GenericCons[U, N, GenericList[U, M]#Transformed[N]] + } +} + +package b { + sealed trait GenericList[L, M[_ >: L]] { + type Transformed[N[MMA >: L]] <: GenericList[L, N] + } + + trait GenericCons[L, M[_ >: L], T <: GenericList[L, M]] extends GenericList[L, M] { + type Transformed[N[MMB >: L]] = GenericCons[L, N, T#Transformed[N]] + } +}
\ No newline at end of file diff --git a/test/files/presentation/callcc-interpreter.check b/test/files/presentation/callcc-interpreter.check index ca99a5afc5..3385ef12b7 100644 --- a/test/files/presentation/callcc-interpreter.check +++ b/test/files/presentation/callcc-interpreter.check @@ -23,7 +23,7 @@ retrieved 64 members `method add(a: callccInterpreter.Value, b: callccInterpreter.Value)callccInterpreter.M[_ >: callccInterpreter.Num with callccInterpreter.Wrong.type <: Product with Serializable with callccInterpreter.Value]` `method apply(a: callccInterpreter.Value, b: callccInterpreter.Value)callccInterpreter.M[callccInterpreter.Value]` `method asInstanceOf[T0]=> T0` -`method callCC[A](h: A => callccInterpreter.M[A] => callccInterpreter.M[A])callccInterpreter.M[A]` +`method callCC[A](h: (A => callccInterpreter.M[A]) => callccInterpreter.M[A])callccInterpreter.M[A]` `method clone()Object` `method ensuring(cond: Boolean)callccInterpreter.type` `method ensuring(cond: Boolean, msg: => Any)callccInterpreter.type` diff --git a/test/files/presentation/ide-bug-1000531.check b/test/files/presentation/ide-bug-1000531.check index 04cea738f5..ae202001eb 100644 --- a/test/files/presentation/ide-bug-1000531.check +++ b/test/files/presentation/ide-bug-1000531.check @@ -101,7 +101,7 @@ retrieved 123 members `method takeWhile(p: B => Boolean)Iterator[B]` `method toArray[B >: B](implicit evidence$1: ClassManifest[B])Array[B]` `method toBuffer[B >: B]=> scala.collection.mutable.Buffer[B]` -`method toIndexedSeq[B >: B]=> scala.collection.immutable.IndexedSeq[B]` +`method toIndexedSeq=> scala.collection.immutable.IndexedSeq[B]` `method toIterable=> Iterable[B]` `method toIterator=> Iterator[B]` `method toList=> List[B]` diff --git a/test/files/run/array-existential-bound.check b/test/files/run/array-existential-bound.check new file mode 100644 index 0000000000..f5cca843e3 --- /dev/null +++ b/test/files/run/array-existential-bound.check @@ -0,0 +1,4 @@ +2 +1000 +1000 +26 diff --git a/test/files/run/array-existential-bound.scala b/test/files/run/array-existential-bound.scala new file mode 100644 index 0000000000..bc442d39f7 --- /dev/null +++ b/test/files/run/array-existential-bound.scala @@ -0,0 +1,17 @@ +trait Fooz[Q <: Array[_]] { + def f0(x: Q) = x.length +} + +object Test extends Fooz[Array[Int]] { + val f1 = new Fooz[Array[String]] { } + val f2 = new Fooz[Array[Int]] { } + val f3 = new Fooz[Array[Any]] { } + val f4 = new Fooz[Array[_]] { } + + def main(args: Array[String]): Unit = { + println(f1.f0(Array[String]("a", "b"))) + println(f2.f0(1 to 1000 toArray)) + println(f3.f0((1 to 1000).toArray[Any])) + println(f4.f0('a' to 'z' toArray)) + } +} diff --git a/test/files/run/interpolation.check b/test/files/run/interpolation.check new file mode 100644 index 0000000000..4c34e4c8c8 --- /dev/null +++ b/test/files/run/interpolation.check @@ -0,0 +1,20 @@ +Bob is 1 years old +Bob is 1 years old +Bob will be 2 years old +Bob will be 2 years old +Bob is 12 years old +Bob is 12 years old +Bob will be 13 years old +Bob will be 13 years old +Bob is 123 years old +Bob is 123 years old +Bob will be 124 years old +Bob will be 124 years old +Best price: 10.0 +Best price: 10.00 +10.0% discount included +10.00% discount included +Best price: 13.345 +Best price: 13.35 +13.345% discount included +13.35% discount included diff --git a/test/files/run/stringInterpolation.flags b/test/files/run/interpolation.flags index 48fd867160..48fd867160 100644 --- a/test/files/run/stringInterpolation.flags +++ b/test/files/run/interpolation.flags diff --git a/test/files/run/interpolation.scala b/test/files/run/interpolation.scala new file mode 100644 index 0000000000..232a180bcd --- /dev/null +++ b/test/files/run/interpolation.scala @@ -0,0 +1,24 @@ +object Test extends App { + + def test1(n: Int) = { + println(s"Bob is $n years old") + println(f"Bob is $n%2d years old") + println(s"Bob will be ${n+1} years old") + println(f"Bob will be ${n+1}%2d years old") + } + + def test2(f: Float) = { + println(s"Best price: $f") + println(f"Best price: $f%.2f") + println(s"$f% discount included") + println(f"$f%3.2f% discount included") + } + + test1(1) + test1(12) + test1(123) + + test2(10.0f) + test2(13.345f) + +} diff --git a/test/files/run/si4147.scala b/test/files/run/si4147.scala new file mode 100644 index 0000000000..c1e2d746a9 --- /dev/null +++ b/test/files/run/si4147.scala @@ -0,0 +1,36 @@ + + + +import scala.collection._ + + + +object Test { + + def main(args: Array[String]) { + checkElementsAreSorted() + checkRangedImpl() + } + + def checkElementsAreSorted() { + val tree = mutable.SortedSet[Int]() + tree ++= List(4, 3, 1, 6, 7, 5, 2) + assert(tree == immutable.SortedSet(1, 2, 3, 4, 5, 6, 7)) + assert(tree.size == 7) + } + + def checkRangedImpl() { + val tree = mutable.SortedSet[Int](3, 1, 6, 7, 5, 2) + val projection = tree.rangeImpl(Some(3), Some(6)) + assert(projection == immutable.SortedSet(3, 5)) + assert(projection.size == 2) + + // Let's check that modification are taken into account + tree add 4 + assert(tree == immutable.SortedSet(1, 2, 3, 4, 5, 6, 7)) + assert(projection == immutable.SortedSet(3, 4, 5)) + assert(tree.size == 7) + assert(projection.size == 3) + } + +} diff --git a/test/files/run/stringInterpolation.check b/test/files/run/stringInterpolation.check deleted file mode 100644 index b5b63343a8..0000000000 --- a/test/files/run/stringInterpolation.check +++ /dev/null @@ -1,2 +0,0 @@ -1 plus 1 is 2 -We have a 1.10% chance of success diff --git a/test/files/run/stringInterpolation.scala b/test/files/run/stringInterpolation.scala deleted file mode 100644 index d88f5f6889..0000000000 --- a/test/files/run/stringInterpolation.scala +++ /dev/null @@ -1,7 +0,0 @@ -object Test { - def main(args : Array[String]) : Unit = { - println("\{1} plus \{1} is \{1 + 1}") - val x = 1.1 - println("We have a \{ x ;2.2f}% chance of success") - } -} diff --git a/test/files/run/t1987.check b/test/files/run/t1987.check new file mode 100644 index 0000000000..d2102a4a18 --- /dev/null +++ b/test/files/run/t1987.check @@ -0,0 +1,16 @@ +long +long +double +double +long +long +double +double +long +long +double +double +long +long +double +double diff --git a/test/files/run/t1987.flags b/test/files/run/t1987.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/run/t1987.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/run/t1987.scala b/test/files/run/t1987.scala new file mode 100644 index 0000000000..4c278ec6a0 --- /dev/null +++ b/test/files/run/t1987.scala @@ -0,0 +1,62 @@ +// a.scala +// Fri Jan 13 11:31:47 PST 2012 + +package foo { + package object bar { + def duh(n: Long) = println("long") + def duh(n: Double) = println("double") + + def duh2(n: Double) = println("double") + def duh2(n: Long) = println("long") + } + package bar { + object Main { + def main(args:Array[String]) { + duh(33L) + bip.bar.duh(33L) + duh(33d) + bip.bar.duh(33d) + + duh2(33L) + bip.bar.duh2(33L) + duh2(33d) + bip.bar.duh2(33d) + } + } + } +} + +package bip { + trait Duh { + def duh(n: Long) = println("long") + def duh(n: Double) = println("double") + } + trait Duh2 { + def duh2(n: Double) = println("double") + def duh2(n: Long) = println("long") + } + + package object bar extends Duh with Duh2 { } + package bar { + object Main { + def main(args:Array[String]) { + duh(33L) + bip.bar.duh(33L) + duh(33d) + bip.bar.duh(33d) + + duh2(33L) + bip.bar.duh2(33L) + duh2(33d) + bip.bar.duh2(33d) + } + } + } +} + +object Test { + def main(args: Array[String]): Unit = { + foo.bar.Main.main(null) + bip.bar.Main.main(null) + } +} diff --git a/test/files/run/t3758.scala b/test/files/run/t3758.scala new file mode 100644 index 0000000000..18750b0a9c --- /dev/null +++ b/test/files/run/t3758.scala @@ -0,0 +1,10 @@ +object Test { + def main(args: Array[String]): Unit = { + assert(classManifest[Array[String]].typeArguments contains classManifest[String]) + assert(classManifest[Array[Int]].typeArguments contains classManifest[Int]) + assert(classManifest[Array[Float]].typeArguments contains classManifest[Float]) + assert(manifest[Array[String]].typeArguments contains manifest[String]) + assert(manifest[Array[Int]].typeArguments contains manifest[Int]) + assert(manifest[Array[Float]].typeArguments contains manifest[Float]) + } +} diff --git a/test/files/run/t5300.scala b/test/files/run/t5300.scala new file mode 100644 index 0000000000..073b29604a --- /dev/null +++ b/test/files/run/t5300.scala @@ -0,0 +1,7 @@ +object Test { + val pf: PartialFunction[Any, Unit] = { case _ => () } + + def main(args: Array[String]): Unit = { + pf orElse pf + } +} diff --git a/test/files/run/t5377.check b/test/files/run/t5377.check new file mode 100644 index 0000000000..7bd0e297bf --- /dev/null +++ b/test/files/run/t5377.check @@ -0,0 +1,18 @@ +1 List(1) +1 List(1) +2 List(1, 2) List(2, 1) +2 List(1, 2) List(2, 1) +2 List(2, 1) List(1, 2) +2 List(2, 1) List(1, 2) +3 List(1, 2, 3) List(1, 3, 2) List(2, 1, 3) List(2, 3, 1) List(3, 1, 2) List(3, 2, 1) +3 List(1, 2, 3) List(1, 3, 2) List(2, 1, 3) List(2, 3, 1) List(3, 1, 2) List(3, 2, 1) +3 List(1, 3, 2) List(1, 2, 3) List(3, 1, 2) List(3, 2, 1) List(2, 1, 3) List(2, 3, 1) +3 List(1, 3, 2) List(1, 2, 3) List(3, 1, 2) List(3, 2, 1) List(2, 1, 3) List(2, 3, 1) +3 List(2, 1, 3) List(2, 3, 1) List(1, 2, 3) List(1, 3, 2) List(3, 2, 1) List(3, 1, 2) +3 List(2, 1, 3) List(2, 3, 1) List(1, 2, 3) List(1, 3, 2) List(3, 2, 1) List(3, 1, 2) +3 List(2, 3, 1) List(2, 1, 3) List(3, 2, 1) List(3, 1, 2) List(1, 2, 3) List(1, 3, 2) +3 List(2, 3, 1) List(2, 1, 3) List(3, 2, 1) List(3, 1, 2) List(1, 2, 3) List(1, 3, 2) +3 List(3, 1, 2) List(3, 2, 1) List(1, 3, 2) List(1, 2, 3) List(2, 3, 1) List(2, 1, 3) +3 List(3, 1, 2) List(3, 2, 1) List(1, 3, 2) List(1, 2, 3) List(2, 3, 1) List(2, 1, 3) +3 List(3, 2, 1) List(3, 1, 2) List(2, 3, 1) List(2, 1, 3) List(1, 3, 2) List(1, 2, 3) +3 List(3, 2, 1) List(3, 1, 2) List(2, 3, 1) List(2, 1, 3) List(1, 3, 2) List(1, 2, 3) diff --git a/test/files/run/t5377.scala b/test/files/run/t5377.scala new file mode 100644 index 0000000000..2e8fb1a6af --- /dev/null +++ b/test/files/run/t5377.scala @@ -0,0 +1,47 @@ +object Test { + def testPermutations1(num: Int, stream: Stream[Int]): Unit = { + val perm = stream.permutations + print(num) + while(perm.hasNext) { + print(" " + perm.next().toList) + } + println() + } + def testPermutations2(num: Int, stream: List[Int]): Unit = { + val perm = stream.permutations + print(num) + while(perm.hasNext) { + print(" " + perm.next().toList) + } + println() + } + + def main(args: Array[String]): Unit = { + testPermutations1(1, Stream(1)) + testPermutations2(1, List(1)) + + testPermutations1(2, Stream(1, 2)) + testPermutations2(2, List(1, 2)) + + testPermutations1(2, Stream(2, 1)) + testPermutations2(2, List(2, 1)) + + testPermutations1(3, Stream(1, 2, 3)) + testPermutations2(3, List(1, 2, 3)) + + testPermutations1(3, Stream(1, 3, 2)) + testPermutations2(3, List(1, 3, 2)) + + testPermutations1(3, Stream(2, 1, 3)) + testPermutations2(3, List(2, 1, 3)) + + testPermutations1(3, Stream(2, 3, 1)) + testPermutations2(3, List(2, 3, 1)) + + testPermutations1(3, Stream(3, 1, 2)) + testPermutations2(3, List(3, 1, 2)) + + testPermutations1(3, Stream(3, 2, 1)) + testPermutations2(3, List(3, 2, 1)) + } +} diff --git a/test/files/run/xml-attribute.check b/test/files/run/xml-attribute.check new file mode 100644 index 0000000000..3ae2034684 --- /dev/null +++ b/test/files/run/xml-attribute.check @@ -0,0 +1,12 @@ +<t></t> +<t></t> +<t></t> +<t></t> +<t></t> +<t b="1" d="2"></t> +<t b="1" d="2"></t> +<t b="1" d="2"></t> +<t a="1" d="2"></t> +<t b="1" d="2"></t> +<t a="1" b="2" c="3"></t> +<t g="1" e="2" p:a="3" f:e="4" mgruhu:ji="5"></t>
\ No newline at end of file diff --git a/test/files/run/xml-attribute.scala b/test/files/run/xml-attribute.scala new file mode 100644 index 0000000000..eb3956c41b --- /dev/null +++ b/test/files/run/xml-attribute.scala @@ -0,0 +1,37 @@ +import xml.Node + +object Test { + def main(args: Array[String]): Unit = { + val noAttr = <t/> + val attrNull = <t a={ null: String }/> + val attrNone = <t a={ None: Option[Seq[Node]] }/> + val preAttrNull = <t p:a={ null: String }/> + val preAttrNone = <t p:a={ None: Option[Seq[Node]] }/> + assert(noAttr == attrNull) + assert(noAttr == attrNone) + assert(noAttr == preAttrNull) + assert(noAttr == preAttrNone) + + println(noAttr) + println(attrNull) + println(attrNone) + println(preAttrNull) + println(preAttrNone) + + val xml1 = <t b="1" d="2"/> + val xml2 = <t a={ null: String } p:a={ null: String } b="1" c={ null: String } d="2"/> + val xml3 = <t b="1" c={ null: String } d="2" a={ null: String } p:a={ null: String }/> + assert(xml1 == xml2) + assert(xml1 == xml3) + + println(xml1) + println(xml2) + println(xml3) + + // Check if attribute order is retained + println(<t a="1" d="2"/>) + println(<t b="1" d="2"/>) + println(<t a="1" b="2" c="3"/>) + println(<t g="1" e="2" p:a="3" f:e="4" mgruhu:ji="5"/>) + } +} diff --git a/test/files/scalacheck/si4147.scala b/test/files/scalacheck/si4147.scala new file mode 100644 index 0000000000..1453440ef1 --- /dev/null +++ b/test/files/scalacheck/si4147.scala @@ -0,0 +1,67 @@ +import org.scalacheck.Prop.forAll +import org.scalacheck.Properties +import org.scalacheck.ConsoleReporter.testStatsEx +import org.scalacheck.Gen +import org.scalacheck.ConsoleReporter + + +import collection.mutable + + +object Test extends Properties("Mutable TreeSet") { + + val generator = Gen.listOfN(1000, Gen.chooseNum(0, 1000)) + + val denseGenerator = Gen.listOfN(1000, Gen.chooseNum(0, 200)) + + property("Insertion doesn't allow duplicates values.") = forAll(generator) { (s: List[Int]) => + { + val t = mutable.TreeSet[Int](s: _*) + t == s.toSet + } + } + + property("Verification of size method validity") = forAll(generator) { (s: List[Int]) => + { + val t = mutable.TreeSet[Int](s: _*) + for (a <- s) { + t -= a + } + t.size == 0 + } + } + + property("All inserted elements are removed") = forAll(generator) { (s: List[Int]) => + { + val t = mutable.TreeSet[Int](s: _*) + for (a <- s) { + t -= a + } + t == Set() + } + } + + property("Elements are sorted.") = forAll(generator) { (s: List[Int]) => + { + val t = mutable.TreeSet[Int](s: _*) + t.toList == s.distinct.sorted + } + } + + property("Implicit CanBuildFrom resolution succeeds as well as the \"same-result-type\" principle.") = + forAll(generator) { (s: List[Int]) => + { + val t = mutable.TreeSet[Int](s: _*) + val t2 = t.map(_ * 2) + t2.isInstanceOf[collection.mutable.TreeSet[Int]] + } + } + + property("A view doesn't expose off bounds elements") = forAll(denseGenerator) { (s: List[Int]) => + { + val t = mutable.TreeSet[Int](s: _*) + val view = t.rangeImpl(Some(50), Some(150)) + view.filter(_ < 50) == Set[Int]() && view.filter(_ >= 150) == Set[Int]() + } + } +} diff --git a/test/files/specialized/spec-hlists.check b/test/files/specialized/spec-hlists.check new file mode 100644 index 0000000000..0ab3339bbc --- /dev/null +++ b/test/files/specialized/spec-hlists.check @@ -0,0 +1,2 @@ +class HCons$mcI$sp +class HCons$mcI$sp diff --git a/test/files/specialized/spec-hlists.scala b/test/files/specialized/spec-hlists.scala new file mode 100644 index 0000000000..8c4ac8f610 --- /dev/null +++ b/test/files/specialized/spec-hlists.scala @@ -0,0 +1,29 @@ +/** Test contributed by Stefan Zeiger showing that HLists can be + * specialized. + */ + +sealed trait HList { + type Self <: HList + + type |: [E] = HCons[E, Self] + + final def |: [@specialized E](elem: E): |: [E] = new HCons[E, Self](elem, this.asInstanceOf[Self]) + + def m[@specialized E, T <: AnyRef](x: E): T = null.asInstanceOf[T] +} + +final class HCons[@specialized H, T <: HList](val head: H, val tail: T) extends HList { + type Self = HCons[H, T] +} + +final object HNil extends HList { + type Self = HNil.type +} + +object Test extends App { + val l1 = new HCons(42, "foo" |: HNil) + println(l1.getClass) + + val l2 = 42 |: "abc" |: HNil + println(l2.getClass) +} diff --git a/test/scaladoc/scala/html/HtmlFactoryTest.scala b/test/scaladoc/scala/html/HtmlFactoryTest.scala index 5b17affbf0..e2687dd510 100644 --- a/test/scaladoc/scala/html/HtmlFactoryTest.scala +++ b/test/scaladoc/scala/html/HtmlFactoryTest.scala @@ -190,9 +190,9 @@ object Test extends Properties("HtmlFactory") { createTemplate("Trac4372.scala") match { case node: scala.xml.Node => { val html = node.toString - html.contains("<span class=\"name\" title=\"gt4s: $plus$colon\">+:</span>") && - html.contains("<span class=\"name\" title=\"gt4s: $minus$colon\">-:</span>") && - html.contains("""<span class="params">(<span name="n">n: <span name="scala.Int" class="extype">Int</span></span>)</span><span class="result">: <span name="scala.Int" class="extype">Int</span></span>""") + html.contains("<span title=\"gt4s: $plus$colon\" class=\"name\">+:</span>") && + html.contains("<span title=\"gt4s: $minus$colon\" class=\"name\">-:</span>") && + html.contains("""<span class="params">(<span name="n">n: <span class="extype" name="scala.Int">Int</span></span>)</span><span class="result">: <span class="extype" name="scala.Int">Int</span></span>""") } case _ => false } diff --git a/tools/epfl-publish b/tools/epfl-publish index e9cd97b3d2..4982f930bb 100755 --- a/tools/epfl-publish +++ b/tools/epfl-publish @@ -1,7 +1,6 @@ #!/usr/bin/env bash # # publishes nightly build if $publish_to is set in environment. -# alternate maven settings.xml file given in $maven_settings. # [[ $# -eq 1 ]] || { @@ -20,21 +19,6 @@ version="$1" exit 1 } -# should not be hardcoded -# adds -Dsettings.file= if fixed path is present -mavenSettingsOption () { - hardcoded_path="/home/linuxsoft/apps/hudson-maven-settings/settings.xml" - - # environment variable - if [[ -n $maven_settings ]]; then - echo -Dsettings.file="$maven_settings" - elif [[ -f $hardcoded_path ]]; then - echo -Dsettings.file="$hardcoded_path" - fi -} - -mavenSettings=${maven_settings:-findMavenSettings} - if [[ -z $publish_to ]]; then echo "Nothing to publish." else @@ -45,6 +29,4 @@ else [[ $version == "2.8.x" ]] || rsync -az build/scaladoc/ "$publish_to/docs" # sbaz [[ -d dists/sbaz ]] && rsync -az dists/sbaz/ "$publish_to/sbaz" - # Deploy the maven artifacts on scala-tools.org - ( cd dists/maven/latest && ant deploy.snapshot $(mavenSettingsOption) ) fi |