diff options
Diffstat (limited to 'src/reflect/scala/reflect')
54 files changed, 1085 insertions, 486 deletions
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 6971175f88..10c2def72a 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -246,13 +246,13 @@ private[reflect] trait BuildUtils { self: Universe => def unapply(tree: Tree): Option[(List[Tree], Tree)] } - def UnliftHelper1[T](unliftable: Unliftable[T]): UnliftHelper1[T] - trait UnliftHelper1[T] { + def UnliftListElementwise[T](unliftable: Unliftable[T]): UnliftListElementwise[T] + trait UnliftListElementwise[T] { def unapply(lst: List[Tree]): Option[List[T]] } - def UnliftHelper2[T](unliftable: Unliftable[T]): UnliftHelper2[T] - trait UnliftHelper2[T] { + def UnliftListOfListsElementwise[T](unliftable: Unliftable[T]): UnliftListOfListsElementwise[T] + trait UnliftListOfListsElementwise[T] { def unapply(lst: List[List[Tree]]): Option[List[List[T]]] } diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala index 50c8aa8779..5b6ff2325c 100644 --- a/src/reflect/scala/reflect/api/Exprs.scala +++ b/src/reflect/scala/reflect/api/Exprs.scala @@ -106,7 +106,7 @@ trait Exprs { self: Universe => * * The corresponding macro implementation should have the following signature (note how the return type denotes path-dependency on x): * {{{ - * object Impls { def foo_impl(c: BlackboxContext)(x: c.Expr[X]): c.Expr[x.value.T] = ... } + * object Impls { def foo_impl(c: Context)(x: c.Expr[X]): c.Expr[x.value.T] = ... } * }}} */ @compileTimeOnly("cannot use value except for signatures of macro implementations") diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala index 3d5a213f2f..54b65166d8 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -169,6 +169,14 @@ trait FlagSets { self: Universe => /** Flag indicating that tree was generated by the compiler */ val SYNTHETIC: FlagSet + + /** Flag indicating that tree represents an enum. + * + * It can only appear at + * - the enum's class + * - enum constants + **/ + val ENUM: FlagSet } /** The empty set of flags diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala index e239b86452..5667d93e29 100644 --- a/src/reflect/scala/reflect/api/Importers.scala +++ b/src/reflect/scala/reflect/api/Importers.scala @@ -34,7 +34,7 @@ package api * {{{ * def staticEval[T](x: T) = macro staticEval[T] * - * def staticEval[T](c: scala.reflect.macros.BlackboxContext)(x: c.Expr[T]) = { + * def staticEval[T](c: scala.reflect.macros.blackbox.Context)(x: c.Expr[T]) = { * // creates a runtime reflection universe to host runtime compilation * import scala.reflect.runtime.{universe => ru} * val mirror = ru.runtimeMirror(c.libraryClassLoader) diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala index a4cd531053..f11b9a5c55 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -29,19 +29,19 @@ package api * Compile-time `Mirror`s make use of only classloader `Mirror`s to load `Symbol`s * by name. * - * The entry point to classloader `Mirror`s is via [[scala.reflect.macros.BlackboxContext#mirror]] or [[scala.reflect.macros.WhiteboxContext#mirror]]. + * The entry point to classloader `Mirror`s is via [[scala.reflect.macros.blackbox.Context#mirror]] or [[scala.reflect.macros.whitebox.Context#mirror]]. * Typical methods which use classloader `Mirror`s include [[scala.reflect.api.Mirror#staticClass]], * [[scala.reflect.api.Mirror#staticModule]], and [[scala.reflect.api.Mirror#staticPackage]]. For * example: * {{{ - * import scala.reflect.macros.BlackboxContext + * import scala.reflect.macros.blackbox.Context * * case class Location(filename: String, line: Int, column: Int) * * object Macros { * def currentLocation: Location = macro impl * - * def impl(c: BlackboxContext): c.Expr[Location] = { + * def impl(c: Context): c.Expr[Location] = { * import c.universe._ * val pos = c.macroApplication.pos * val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object @@ -153,7 +153,7 @@ package api * * '''[[scala.reflect.api.Mirrors#ClassMirror]]'''. Used for creating invoker mirrors for constructors. * Entry points: for ''static classes'' `val cm1 = m.reflectClass(<class symbol>)`, - * for ''inner classes'' `val mm2 = im.reflectClass(<module symbol>)`. + * for ''inner classes'' `val mm2 = im.reflectClass(<class symbol>)`. * Example: * {{{ * scala> case class C(x: Int) diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala index 1e0854d171..5bc92d3893 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -201,6 +201,25 @@ trait Printers { self: Universe => */ protected def newTreePrinter(out: PrintWriter): TreePrinter + /** + * Renders the code of the passed tree, so that: + * 1) it can be later compiled by scalac retaining the same meaning, + * 2) it looks pretty. + * At the moment we have handled #1 for unattributed trees and + * later on plan to account for typical idiosyncrasies of the typechecker. + * #2 is more or less okay indentation-wise, but at the moment there's a lot of desugaring + * left in place, and that's what we also plan to improve in the future. + * + * @group Printers + */ + def showCode(tree: Tree) = render(tree, newCodePrinter) + + /** + * Hook to define what `showCode(...)` means. + * @group Printers + */ + protected def newCodePrinter(out: PrintWriter): TreePrinter + /** Renders internal structure of a reflection artifact as the * visualization of a Scala syntax tree. * diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala index 6756d5e114..5a03996dd9 100644 --- a/src/reflect/scala/reflect/api/StandardLiftables.scala +++ b/src/reflect/scala/reflect/api/StandardLiftables.scala @@ -11,16 +11,16 @@ trait StandardLiftables { self: Universe => private def callCollection(name: Name)(args: List[Tree]) = callScala(nme.collection, nme.immutable, name)(args) private def liftAsLiteral[T]: Liftable[T] = Liftable { v => Literal(Constant(v)) } - implicit def liftByte[T <: Byte]: Liftable[T] = liftAsLiteral[T] - implicit def liftShort[T <: Short]: Liftable[T] = liftAsLiteral[T] - implicit def liftChar[T <: Char]: Liftable[T] = liftAsLiteral[T] - implicit def liftInt[T <: Int]: Liftable[T] = liftAsLiteral[T] - implicit def liftLong[T <: Long]: Liftable[T] = liftAsLiteral[T] - implicit def liftFloat[T <: Float]: Liftable[T] = liftAsLiteral[T] - implicit def liftDouble[T <: Double]: Liftable[T] = liftAsLiteral[T] - implicit def liftBoolean: Liftable[Boolean] = liftAsLiteral[Boolean] - implicit def liftUnit: Liftable[Unit] = liftAsLiteral[Unit] - implicit def liftString: Liftable[String] = liftAsLiteral[String] + implicit def liftByte[T <: Byte]: Liftable[T] = liftAsLiteral[T] + implicit def liftShort[T <: Short]: Liftable[T] = liftAsLiteral[T] + implicit def liftChar[T <: Char]: Liftable[T] = liftAsLiteral[T] + implicit def liftInt[T <: Int]: Liftable[T] = liftAsLiteral[T] + implicit def liftLong[T <: Long]: Liftable[T] = liftAsLiteral[T] + implicit def liftFloat[T <: Float]: Liftable[T] = liftAsLiteral[T] + implicit def liftDouble[T <: Double]: Liftable[T] = liftAsLiteral[T] + implicit def liftBoolean[T <: Boolean]: Liftable[T] = liftAsLiteral[T] + implicit def liftUnit: Liftable[Unit] = liftAsLiteral[Unit] + implicit def liftString[T <: String]: Liftable[T] = liftAsLiteral[T] implicit def liftScalaSymbol: Liftable[scala.Symbol] = Liftable { v => callScala(nme.Symbol)(Literal(Constant(v.name)) :: Nil) @@ -35,16 +35,22 @@ trait StandardLiftables { self: Universe => implicit def liftArray[T: Liftable]: Liftable[Array[T]] = Liftable { arr => callScala(nme.Array)(arr.map(lift(_)).toList) } implicit def liftVector[T: Liftable]: Liftable[Vector[T]] = Liftable { vect => callCollection(nme.Vector)(vect.map(lift(_)).toList) } implicit def liftList[T: Liftable]: Liftable[List[T]] = Liftable { lst => callCollection(nme.List)(lst.map(lift(_))) } + implicit def liftNil: Liftable[Nil.type] = Liftable { _ => selectScala(nme.collection, nme.immutable, nme.Nil) } implicit def liftMap[K: Liftable, V: Liftable]: Liftable[Map[K, V]] = Liftable { m => callCollection(nme.Map)(m.toList.map(lift(_))) } implicit def liftSet[T: Liftable]: Liftable[Set[T]] = Liftable { s => callCollection(nme.Set)(s.toList.map(lift(_))) } + implicit def liftSome[T: Liftable]: Liftable[Some[T]] = Liftable { case Some(v) => callScala(nme.Some)(lift(v) :: Nil) } + implicit def liftNone: Liftable[None.type] = Liftable { _ => selectScala(nme.None) } implicit def liftOption[T: Liftable]: Liftable[Option[T]] = Liftable { - case Some(v) => callScala(nme.Some)(lift(v) :: Nil) - case None => selectScala(nme.None) + case some: Some[T] => lift(some) + case none: None.type => lift(none) } + + implicit def liftLeft[L: Liftable, R]: Liftable[Left[L, R]] = Liftable { case Left(v) => callScala(nme.util, nme.Left)(lift(v) :: Nil) } + implicit def liftRight[L, R: Liftable]: Liftable[Right[L, R]] = Liftable { case Right(v) => callScala(nme.util, nme.Right)(lift(v) :: Nil) } implicit def liftEither[L: Liftable, R: Liftable]: Liftable[Either[L, R]] = Liftable { - case Left(l) => callScala(nme.util, nme.Left)(lift(l) :: Nil) - case Right(r) => callScala(nme.util, nme.Right)(lift(r) :: Nil) + case left: Left[L, R] => lift(left) + case right: Right[L, R] => lift(right) } implicit def liftTuple1[T1](implicit liftT1: Liftable[T1]): Liftable[Tuple1[T1]] = Liftable { t => @@ -220,6 +226,7 @@ trait StandardLiftables { self: Universe => val List = TermName("List") val Map = TermName("Map") val None = TermName("None") + val Nil = TermName("Nil") val Right = TermName("Right") val Set = TermName("Set") val Some = TermName("Some") diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala index 9d2d06da69..4892b46e16 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -707,14 +707,14 @@ trait Types { val AnnotatedType: AnnotatedTypeExtractor /** An extractor class to create and pattern match with syntax - * `AnnotatedType(annotations, underlying, selfsym)`. + * `AnnotatedType(annotations, underlying)`. * Here, `annotations` are the annotations decorating the underlying type `underlying`. * `selfSym` is a symbol representing the annotated type itself. * @group Extractors */ abstract class AnnotatedTypeExtractor { - def apply(annotations: List[Annotation], underlying: Type, selfsym: Symbol): AnnotatedType - def unapply(tpe: AnnotatedType): Option[(List[Annotation], Type, Symbol)] + def apply(annotations: List[Annotation], underlying: Type): AnnotatedType + def unapply(tpe: AnnotatedType): Option[(List[Annotation], Type)] } /** The API that all annotated types support. @@ -727,9 +727,6 @@ trait Types { /** The annotee. */ def underlying: Type - - /** A symbol that represents the annotated type itself. */ - def selfsym: Symbol } /** The `TypeBounds` type signature is used to indicate lower and upper type bounds diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index 1da2c24306..1c9b77581a 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -41,11 +41,11 @@ package api * res1: reflect.runtime.universe.Type = scala.Either[String,Int] * }}} * - * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.BlackboxContext#universe]]. - * or [[scala.reflect.macros.WhiteboxContext#universe]]. For example: + * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.blackbox.Context#universe]]. + * or [[scala.reflect.macros.whitebox.Context#universe]]. For example: * {{{ * def printf(format: String, params: Any*): Unit = macro impl - * def impl(c: BlackboxContext)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = { + * def impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = { * import c.universe._ * ... * } diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index f45fa40f89..4fde57ed02 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -290,8 +290,8 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => * metaAnnotations = List(setter, field). */ def metaAnnotations: List[AnnotationInfo] = atp match { - case AnnotatedType(metas, _, _) => metas - case _ => Nil + case AnnotatedType(metas, _) => metas + case _ => Nil } /** The default kind of members to which this annotation is attached. diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala index 19c67879f5..0ca8611719 100644 --- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala +++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala @@ -166,9 +166,10 @@ trait BaseTypeSeqs { val index = new Array[Int](nparents) var i = 0 for (p <- parents) { + val parentBts = p.dealias.baseTypeSeq // dealias need for SI-8046. pbtss(i) = - if (p.baseTypeSeq eq undetBaseTypeSeq) AnyClass.info.baseTypeSeq - else p.baseTypeSeq + if (parentBts eq undetBaseTypeSeq) AnyClass.info.baseTypeSeq + else parentBts index(i) = 0 i += 1 } diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 0a81bfa2a5..9b19dc11cb 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -455,14 +455,14 @@ trait BuildUtils { self: SymbolTable => } } - def UnliftHelper1[T](unliftable: Unliftable[T]) = new UnliftHelper1[T] { + def UnliftListElementwise[T](unliftable: Unliftable[T]) = new UnliftListElementwise[T] { def unapply(lst: List[Tree]): Option[List[T]] = { val unlifted = lst.flatMap { unliftable.unapply(_) } if (unlifted.length == lst.length) Some(unlifted) else None } } - def UnliftHelper2[T](unliftable: Unliftable[T]) = new UnliftHelper2[T] { + def UnliftListOfListsElementwise[T](unliftable: Unliftable[T]) = new UnliftListOfListsElementwise[T] { def unapply(lst: List[List[Tree]]): Option[List[List[T]]] = { val unlifted = lst.map { l => l.flatMap { unliftable.unapply(_) } } if (unlifted.flatten.length == lst.flatten.length) Some(unlifted) else None diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 38be6fcf56..c2939e69b5 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -363,6 +363,7 @@ trait Definitions extends api.StandardDefinitions { lazy val ComparableClass = requiredClass[java.lang.Comparable[_]] modifyInfo fixupAsAnyTrait lazy val JavaCloneableClass = requiredClass[java.lang.Cloneable] lazy val JavaNumberClass = requiredClass[java.lang.Number] + lazy val JavaEnumClass = requiredClass[java.lang.Enum[_]] lazy val RemoteInterfaceClass = requiredClass[java.rmi.Remote] lazy val RemoteExceptionClass = requiredClass[java.rmi.RemoteException] @@ -482,12 +483,8 @@ trait Definitions extends api.StandardDefinitions { lazy val TypeCreatorClass = getClassIfDefined("scala.reflect.api.TypeCreator") // defined in scala-reflect.jar, so we need to be careful lazy val TreeCreatorClass = getClassIfDefined("scala.reflect.api.TreeCreator") // defined in scala-reflect.jar, so we need to be careful - lazy val BlackboxMacroClass = getClassIfDefined("scala.reflect.macros.BlackboxMacro") // defined in scala-reflect.jar, so we need to be careful - def BlackboxMacroContextValue = BlackboxMacroClass.map(sym => getMemberValue(sym, nme.c)) - lazy val WhiteboxMacroClass = getClassIfDefined("scala.reflect.macros.WhiteboxMacro") // defined in scala-reflect.jar, so we need to be careful - def WhiteboxMacroContextValue = WhiteboxMacroClass.map(sym => getMemberValue(sym, nme.c)) - lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.BlackboxContext") // defined in scala-reflect.jar, so we need to be careful - lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.WhiteboxContext") // defined in scala-reflect.jar, so we need to be careful + lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.blackbox.Context") // defined in scala-reflect.jar, so we need to be careful + lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.whitebox.Context") // defined in scala-reflect.jar, so we need to be careful def MacroContextPrefix = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.prefix)) def MacroContextPrefixType = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.PrefixType)) def MacroContextUniverse = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.universe)) @@ -603,32 +600,31 @@ trait Definitions extends api.StandardDefinitions { def isWhiteboxContextType(tp: Type) = isMacroContextType(tp) && (tp <:< WhiteboxContextClass.tpe) - def mightBeMacroBundleType(tp: Type) = - tp.baseClasses.contains(WhiteboxMacroClass) || - tp.baseClasses.contains(BlackboxMacroClass) - - def isMacroBundleType(tp: Type) = tp.baseClasses match { - case _ :: proto :: _ if isMacroBundleProtoType(proto.tpe) => true - case _ => false + private def macroBundleParamInfo(tp: Type) = { + val ctor = tp.erasure.typeSymbol.primaryConstructor + ctor.paramss match { + case List(List(c)) => + val sym = c.info.typeSymbol + val isContextCompatible = sym.isNonBottomSubClass(BlackboxContextClass) || sym.isNonBottomSubClass(WhiteboxContextClass) + if (isContextCompatible) c.info else NoType + case _ => + NoType + } } - def isBlackboxMacroBundleType(tp: Type) = - isMacroBundleType(tp) && (tp <:< BlackboxMacroClass.tpe) && !(tp <:< WhiteboxMacroClass.tpe) + def looksLikeMacroBundleType(tp: Type) = + macroBundleParamInfo(tp) != NoType - def isMacroBundleProtoType(tp: Type) = { - val sym = tp.typeSymbol - val isNonTrivial = tp != ErrorType && tp != NothingTpe && tp != NullTpe - def subclasses(sym: Symbol) = sym != NoSymbol && tp.baseClasses.contains(sym) - val isMacroCompatible = subclasses(BlackboxMacroClass) ^ subclasses(WhiteboxMacroClass) - val isBundlePrototype = sym != BlackboxMacroClass && sym != WhiteboxMacroClass && sym.isTrait && { - val c = sym.info.member(nme.c) - def overrides(sym: Symbol) = c.overrideChain.contains(sym) - val cIsOk = (overrides(BlackboxMacroContextValue) || overrides(WhiteboxMacroContextValue)) && c.isDeferred - cIsOk && sym.isMonomorphicType - } - isNonTrivial && isMacroCompatible && isBundlePrototype + def isMacroBundleType(tp: Type) = { + val isContextCompatible = macroBundleParamInfo(tp) != NoType + val hasSingleConstructor = !tp.declaration(nme.CONSTRUCTOR).isOverloaded + val nonAbstract = !tp.erasure.typeSymbol.isAbstractClass + isContextCompatible && hasSingleConstructor && nonAbstract } + def isBlackboxMacroBundleType(tp: Type) = + isMacroBundleType(tp) && (macroBundleParamInfo(tp) <:< BlackboxContextClass.tpe) + def isIterableType(tp: Type) = tp <:< classExistentialType(IterableClass) // These "direct" calls perform no dealiasing. They are most needed when @@ -692,7 +688,7 @@ trait Definitions extends api.StandardDefinitions { case TypeRef(pre, sym, _) if sym.isModuleClass => isStable(pre) case TypeRef(_, _, _) if tp ne tp.dealias => isStable(tp.dealias) case TypeVar(origin, _) => isStable(origin) - case AnnotatedType(_, atp, _) => isStable(atp) // Really? + case AnnotatedType(_, atp) => isStable(atp) // Really? case _: SimpleTypeProxy => isStable(tp.underlying) case _ => false } @@ -812,46 +808,32 @@ trait Definitions extends api.StandardDefinitions { def byNameType(arg: Type) = appliedType(ByNameParamClass, arg) def iteratorOfType(tp: Type) = appliedType(IteratorClass, tp) def javaRepeatedType(arg: Type) = appliedType(JavaRepeatedParamClass, arg) + def optionType(tp: Type) = appliedType(OptionClass, tp) def scalaRepeatedType(arg: Type) = appliedType(RepeatedParamClass, arg) def seqType(arg: Type) = appliedType(SeqClass, arg) // FYI the long clunky name is because it's really hard to put "get" into the // name of a method without it sounding like the method "get"s something, whereas // this method is about a type member which just happens to be named get. - def typeOfMemberNamedGet(tp: Type) = resultOfMatchingMethod(tp, nme.get)() - def typeOfMemberNamedHead(tp: Type) = resultOfMatchingMethod(tp, nme.head)() - def typeOfMemberNamedApply(tp: Type) = resultOfMatchingMethod(tp, nme.apply)(IntTpe) - def typeOfMemberNamedDrop(tp: Type) = resultOfMatchingMethod(tp, nme.drop)(IntTpe) - def typeOfMemberNamedGetOrSelf(tp: Type) = typeOfMemberNamedGet(tp) orElse tp - def typesOfSelectors(tp: Type) = getterMemberTypes(tp, productSelectors(tp)) - def typesOfCaseAccessors(tp: Type) = getterMemberTypes(tp, tp.typeSymbol.caseFieldAccessors) - - /** If this is a case class, the case field accessors (which may be an empty list.) - * Otherwise, if there are any product selectors, that list. - * Otherwise, a list containing only the type itself. - */ - def typesOfSelectorsOrSelf(tp: Type): List[Type] = ( - if (tp.typeSymbol.isCase) - typesOfCaseAccessors(tp) - else typesOfSelectors(tp) match { - case Nil => tp :: Nil - case tps => tps - } - ) - - /** If the given type has one or more product selectors, the type of the last one. - * Otherwise, the type itself. - */ - def typeOfLastSelectorOrSelf(tp: Type) = typesOfSelectorsOrSelf(tp).last - - def elementTypeOfLastSelectorOrSelf(tp: Type) = { - val last = typeOfLastSelectorOrSelf(tp) - ( typeOfMemberNamedHead(last) - orElse typeOfMemberNamedApply(last) - orElse elementType(ArrayClass, last) - ) + def typeOfMemberNamedGet(tp: Type) = typeArgOfBaseTypeOr(tp, OptionClass)(resultOfMatchingMethod(tp, nme.get)()) + def typeOfMemberNamedHead(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.head)()) + def typeOfMemberNamedApply(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.apply)(IntTpe)) + def typeOfMemberNamedDrop(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.drop)(IntTpe)) + def typesOfSelectors(tp: Type) = getterMemberTypes(tp, productSelectors(tp)) + // SI-8128 Still using the type argument of the base type at Seq/Option if this is an old-style (2.10 compatible) + // extractor to limit exposure to regressions like the reported problem with existentials. + // TODO fix the existential problem in the general case, see test/pending/pos/t8128.scala + private def typeArgOfBaseTypeOr(tp: Type, baseClass: Symbol)(or: => Type): Type = (tp baseType baseClass).typeArgs match { + case x :: Nil => x + case _ => or } + // Can't only check for _1 thanks to pos/t796. + def hasSelectors(tp: Type) = ( + (tp.members containsName nme._1) + && (tp.members containsName nme._2) + ) + /** Returns the method symbols for members _1, _2, ..., _N * which exist in the given type. */ @@ -861,7 +843,9 @@ trait Definitions extends api.StandardDefinitions { case m if m.paramss.nonEmpty => Nil case m => m :: loop(n + 1) } - loop(1) + // Since ErrorType always returns a symbol from a call to member, we + // had better not start looking for _1, _2, etc. expecting it to run out. + if (tpe.isErroneous) Nil else loop(1) } /** If `tp` has a term member `name`, the first parameter list of which diff --git a/src/reflect/scala/reflect/internal/FlagSets.scala b/src/reflect/scala/reflect/internal/FlagSets.scala index 84825ff2da..799f85054a 100644 --- a/src/reflect/scala/reflect/internal/FlagSets.scala +++ b/src/reflect/scala/reflect/internal/FlagSets.scala @@ -43,5 +43,6 @@ trait FlagSets extends api.FlagSets { self: SymbolTable => val PRESUPER : FlagSet = Flags.PRESUPER val DEFAULTINIT : FlagSet = Flags.DEFAULTINIT val SYNTHETIC : FlagSet = Flags.SYNTHETIC + val ENUM : FlagSet = Flags.ENUM } } diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index dcdf6728ce..e66ed9a3d4 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -63,7 +63,7 @@ import scala.collection.{ mutable, immutable } // 45: SYNCHRONIZED/M // 46: ARTIFACT // 47: DEFAULTMETHOD/M -// 48: +// 48: ENUM // 49: // 50: // 51: lateDEFERRED @@ -119,6 +119,7 @@ class ModifierFlags { final val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode final val DEFAULTMETHOD = 1L << 47 // symbol is a java default method + final val ENUM = 1L << 48 // symbol is an enum /** Symbols which are marked ARTIFACT. (Expand this list?) * @@ -142,7 +143,7 @@ class ModifierFlags { } object ModifierFlags extends ModifierFlags -/** All flags and associated operatins */ +/** All flags and associated operations */ class Flags extends ModifierFlags { final val METHOD = 1 << 6 // a method final val MODULE = 1 << 8 // symbol is module or class implementing a module @@ -446,7 +447,7 @@ class Flags extends ModifierFlags { case SYNCHRONIZED => "<synchronized>" // (1L << 45) case ARTIFACT => "<artifact>" // (1L << 46) case DEFAULTMETHOD => "<defaultmethod>" // (1L << 47) - case 0x1000000000000L => "" // (1L << 48) + case ENUM => "<enum>" // (1L << 48) case 0x2000000000000L => "" // (1L << 49) case 0x4000000000000L => "" // (1L << 50) case `lateDEFERRED` => "<latedeferred>" // (1L << 51) @@ -478,7 +479,7 @@ class Flags extends ModifierFlags { ) @deprecated("Use flagString on the flag-carrying member", "2.10.0") - def flagsToString(flags: Long, privateWithin: String): String = { + private[scala] def flagsToString(flags: Long, privateWithin: String): String = { val access = accessString(flags, privateWithin) val nonAccess = flagsToString(flags & ~AccessFlags) @@ -486,7 +487,7 @@ class Flags extends ModifierFlags { } @deprecated("Use flagString on the flag-carrying member", "2.10.0") - def flagsToString(flags: Long): String = { + private[scala] def flagsToString(flags: Long): String = { // Fast path for common case if (flags == 0L) "" else { var sb: StringBuilder = null diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala index ecbf839bab..1131c94da0 100644 --- a/src/reflect/scala/reflect/internal/HasFlags.scala +++ b/src/reflect/scala/reflect/internal/HasFlags.scala @@ -82,6 +82,7 @@ trait HasFlags { def hasAbstractFlag = hasFlag(ABSTRACT) def hasAccessorFlag = hasFlag(ACCESSOR) def hasDefault = hasFlag(DEFAULTPARAM) && hasFlag(METHOD | PARAM) // Second condition disambiguates with TRAIT + def hasEnumFlag = hasFlag(ENUM) def hasLocalFlag = hasFlag(LOCAL) def hasModuleFlag = hasFlag(MODULE) def hasPackageFlag = hasFlag(PACKAGE) diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index 26d55e21c4..483d0dd656 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -268,8 +268,8 @@ trait Importers extends api.Importers { to: SymbolTable => val myconstr = new TypeConstraint(their.constr.loBounds map importType, their.constr.hiBounds map importType) myconstr.inst = importType(their.constr.inst) TypeVar(importType(their.origin), myconstr, their.typeArgs map importType, their.params map importSymbol) - case from.AnnotatedType(annots, result, selfsym) => - AnnotatedType(annots map importAnnotationInfo, importType(result), importSymbol(selfsym)) + case from.AnnotatedType(annots, result) => + AnnotatedType(annots map importAnnotationInfo, importType(result)) case from.ErrorType => ErrorType case from.WildcardType => diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 9c5a593ca5..6cf4944d18 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -186,6 +186,15 @@ trait Mirrors extends api.Mirrors { def getPackageObjectIfDefined(fullname: TermName): Symbol = wrapMissing(getPackageObject(fullname)) + + final def getPackageObjectWithMember(pre: Type, sym: Symbol): Symbol = { + // The owner of a symbol which requires package qualification may be the + // package object iself, but it also could be any superclass of the package + // object. In the latter case, we must go through the qualifier's info + // to obtain the right symbol. + if (sym.owner.isModuleClass) sym.owner.sourceModule // fast path, if the member is owned by a module class, that must be linked to the package object + else pre member nme.PACKAGE // otherwise we have to findMember + } override def staticPackage(fullname: String): ModuleSymbol = ensurePackageSymbol(fullname.toString, getModuleOrClass(newTermNameCached(fullname)), allowModules = false) diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 424e73dce8..519d1047a6 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -17,8 +17,6 @@ trait Printers extends api.Printers { self: SymbolTable => //nsc import treeInfo.{ IsTrue, IsFalse } - final val showOuterTests = false - /** Adds backticks if the name is a scala keyword. */ def quotedName(name: Name, decode: Boolean): String = { val s = if (decode) name.decode else name.toString @@ -53,8 +51,8 @@ trait Printers extends api.Printers { self: SymbolTable => */ def backquotedPath(t: Tree): String = { t match { - case Select(qual, name) if name.isTermName => "%s.%s".format(backquotedPath(qual), symName(t, name)) - case Select(qual, name) if name.isTypeName => "%s#%s".format(backquotedPath(qual), symName(t, name)) + case Select(qual, name) if name.isTermName => s"${backquotedPath(qual)}.${symName(t, name)}" + case Select(qual, name) if name.isTypeName => s"${backquotedPath(qual)}#${symName(t, name)}" case Ident(name) => symName(t, name) case _ => t.toString } @@ -76,7 +74,7 @@ trait Printers extends api.Printers { self: SymbolTable => def printPosition(tree: Tree) = if (printPositions) print(tree.pos.show) - def println() { + def println() = { out.println() while (indentMargin > indentString.length()) indentString += indentString @@ -84,116 +82,221 @@ trait Printers extends api.Printers { self: SymbolTable => out.write(indentString, 0, indentMargin) } - def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) { + def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit): Unit = ls match { case List() => case List(x) => printelem(x) case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep) } - } - def printColumn(ts: List[Tree], start: String, sep: String, end: String) { + def printColumn(ts: List[Tree], start: String, sep: String, end: String) = { print(start); indent(); println() printSeq(ts){print(_)}{print(sep); println()}; undent(); println(); print(end) } - def printRow(ts: List[Tree], start: String, sep: String, end: String) { + def printRow(ts: List[Tree], start: String, sep: String, end: String): Unit = { print(start); printSeq(ts){print(_)}{print(sep)}; print(end) } - def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") } + def printRow(ts: List[Tree], sep: String): Unit = printRow(ts, "", sep, "") - def printTypeParams(ts: List[TypeDef]) { - if (!ts.isEmpty) { + def printTypeParams(ts: List[TypeDef]): Unit = + if (ts.nonEmpty) { print("["); printSeq(ts){ t => printAnnotations(t) + if (t.mods.hasFlag(CONTRAVARIANT)) { + print("-") + } else if (t.mods.hasFlag(COVARIANT)) { + print("+") + } printParam(t) }{print(", ")}; print("]") } - } - def printLabelParams(ps: List[Ident]) { + def printLabelParams(ps: List[Ident]) = { print("(") printSeq(ps){printLabelParam}{print(", ")} print(")") } - def printLabelParam(p: Ident) { + def printLabelParam(p: Ident) = { print(symName(p, p.name)); printOpt(": ", TypeTree() setType p.tpe) } - def printValueParams(ts: List[ValDef]) { - print("(") - if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "") - printSeq(ts){printParam}{print(", ")} - print(")") + protected def parenthesize(condition: Boolean = true)(body: => Unit) = { + if (condition) print("(") + body + if (condition) print(")") } + + protected def printImplicitInParamsList(vds: List[ValDef]) = + if (vds.nonEmpty) printFlags(vds.head.mods.flags & IMPLICIT, "") + + def printValueParams(ts: List[ValDef], inParentheses: Boolean = true): Unit = + parenthesize(inParentheses){ + printImplicitInParamsList(ts) + printSeq(ts){printParam}{print(", ")} + } - def printParam(tree: Tree) { + def printParam(tree: Tree) = tree match { - case ValDef(mods, name, tp, rhs) => + case vd @ ValDef(mods, name, tp, rhs) => printPosition(tree) - printAnnotations(tree) + printAnnotations(vd) print(symName(tree, name)); printOpt(": ", tp); printOpt(" = ", rhs) case TypeDef(mods, name, tparams, rhs) => printPosition(tree) print(symName(tree, name)) printTypeParams(tparams); print(rhs) } - } - def printBlock(tree: Tree) { + def printBlock(tree: Tree) = tree match { case Block(_, _) => print(tree) case _ => printColumn(List(tree), "{", ";", "}") } - } private def symFn[T](tree: Tree, f: Symbol => T, orElse: => T): T = tree.symbol match { - case null | NoSymbol => orElse - case sym => f(sym) + case null | NoSymbol => orElse + case sym => f(sym) } private def ifSym(tree: Tree, p: Symbol => Boolean) = symFn(tree, p, false) - def printOpt(prefix: String, tree: Tree) { - if (!tree.isEmpty) { print(prefix, tree) } - } + def printOpt(prefix: String, tree: Tree) = if (tree.nonEmpty) { print(prefix, tree) } def printModifiers(tree: Tree, mods: Modifiers): Unit = printFlags( - if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + ( - if (tree.symbol == NoSymbol) mods.privateWithin - else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name - else "" + if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + ( + if (tree.symbol == NoSymbol) mods.privateWithin + else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name + else "" ) ) - def printFlags(flags: Long, privateWithin: String) { + def printFlags(flags: Long, privateWithin: String) = { val mask: Long = if (settings.debug) -1L else PrintableFlags val s = flagsToString(flags & mask, privateWithin) if (s != "") print(s + " ") } - def printAnnotations(tree: Tree) { + def printAnnotations(tree: MemberDef) = { // SI-5885: by default this won't print annotations of not yet initialized symbols val annots = tree.symbol.annotations match { - case Nil => tree.asInstanceOf[MemberDef].mods.annotations + case Nil => tree.mods.annotations case anns => anns } - annots foreach (annot => print("@"+annot+" ")) + annots foreach (annot => print(s"@$annot ")) } private var currentOwner: Symbol = NoSymbol private var selectorType: Type = NoType + + protected def printPackageDef(tree: PackageDef, separator: String) = { + val PackageDef(packaged, stats) = tree + printAnnotations(tree) + print("package ", packaged); printColumn(stats, " {", separator, "}") + } + + protected def printValDef(tree: ValDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) = { + val ValDef(mods, name, tp, rhs) = tree + printAnnotations(tree) + printModifiers(tree, mods) + print(if (mods.isMutable) "var " else "val ", resultName) + printTypeSignature + printRhs + } + + protected def printDefDef(tree: DefDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) = { + val DefDef(mods, name, tparams, vparamss, tp, rhs) = tree + printAnnotations(tree) + printModifiers(tree, mods) + print("def " + resultName) + printTypeParams(tparams); + vparamss foreach {printValueParams(_)} + printTypeSignature + printRhs + } + + protected def printTypeDef(tree: TypeDef, resultName: => String) = { + val TypeDef(mods, name, tparams, rhs) = tree + if (mods hasFlag (PARAM | DEFERRED)) { + printAnnotations(tree) + printModifiers(tree, mods) + print("type ") + printParam(tree) + } else { + printAnnotations(tree) + printModifiers(tree, mods) + print("type " + resultName) + printTypeParams(tparams) + printOpt(" = ", rhs) + } + } + + protected def printImport(tree: Import, resSelect: => String) = { + val Import(expr, selectors) = tree + // Is this selector renaming a name (i.e, {name1 => name2}) + def isNotRename(s: ImportSelector): Boolean = + s.name == nme.WILDCARD || s.name == s.rename + + def selectorToString(s: ImportSelector): String = { + val from = quotedName(s.name) + if (isNotRename(s)) from + else from + "=>" + quotedName(s.rename) + } + print("import ", resSelect, ".") + selectors match { + case List(s) => + // If there is just one selector and it is not renaming a name, no braces are needed + if (isNotRename(s)) print(selectorToString(s)) + else print("{", selectorToString(s), "}") + // If there is more than one selector braces are always needed + case many => + print(many.map(selectorToString).mkString("{", ", ", "}")) + } + } + + protected def printCaseDef(tree: CaseDef) = { + val CaseDef(pat, guard, body) = tree + print("case ") + def patConstr(pat: Tree): Tree = pat match { + case Apply(fn, args) => patConstr(fn) + case _ => pat + } + + print(pat); printOpt(" if ", guard) + print(" => ", body) + } + + protected def printFunction(tree: Function)(printValueParams: => Unit) = { + val Function(vparams, body) = tree + print("("); + printValueParams + print(" => ", body, ")") + if (printIds && tree.symbol != null) print("#" + tree.symbol.id) + } + + protected def printSuper(tree: Super, resultName: => String) = { + val Super(This(qual), mix) = tree + if (qual.nonEmpty || tree.symbol != NoSymbol) print(resultName + ".") + print("super") + if (mix.nonEmpty) print(s"[$mix]") + } + + protected def printThis(tree: This, resultName: => String) = { + val This(qual) = tree + if (qual.nonEmpty) print(resultName + ".") + print("this") + } - def printTree(tree: Tree) { + def printTree(tree: Tree) = { tree match { case EmptyTree => print("<empty>") - case ClassDef(mods, name, tparams, impl) => - printAnnotations(tree) + case cd @ ClassDef(mods, name, tparams, impl) => + printAnnotations(cd) printModifiers(tree, mods) val word = if (mods.isTrait) "trait" @@ -204,81 +307,45 @@ trait Printers extends api.Printers { self: SymbolTable => printTypeParams(tparams) print(if (mods.isDeferred) " <: " else " extends ", impl) - case PackageDef(packaged, stats) => - printAnnotations(tree) - print("package ", packaged); printColumn(stats, " {", ";", "}") + case pd @ PackageDef(packaged, stats) => + printPackageDef(pd, ";") - case ModuleDef(mods, name, impl) => - printAnnotations(tree) + case md @ ModuleDef(mods, name, impl) => + printAnnotations(md) printModifiers(tree, mods) print("object " + symName(tree, name), " extends ", impl) - case ValDef(mods, name, tp, rhs) => - printAnnotations(tree) - printModifiers(tree, mods) - print(if (mods.isMutable) "var " else "val ", symName(tree, name)) - printOpt(": ", tp) - if (!mods.isDeferred) - print(" = ", if (rhs.isEmpty) "_" else rhs) + case vd @ ValDef(mods, name, tp, rhs) => + printValDef(vd, symName(tree, name))(printOpt(": ", tp)) { + if (!mods.isDeferred) print(" = ", if (rhs.isEmpty) "_" else rhs) + } - case DefDef(mods, name, tparams, vparamss, tp, rhs) => - printAnnotations(tree) - printModifiers(tree, mods) - print("def " + symName(tree, name)) - printTypeParams(tparams); vparamss foreach printValueParams - printOpt(": ", tp); printOpt(" = ", rhs) + case dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) => + printDefDef(dd, symName(tree, name))(printOpt(": ", tp))(printOpt(" = ", rhs)) - case TypeDef(mods, name, tparams, rhs) => - if (mods hasFlag (PARAM | DEFERRED)) { - printAnnotations(tree) - printModifiers(tree, mods); print("type "); printParam(tree) - } else { - printAnnotations(tree) - printModifiers(tree, mods); print("type " + symName(tree, name)) - printTypeParams(tparams); printOpt(" = ", rhs) - } + case td @ TypeDef(mods, name, tparams, rhs) => + printTypeDef(td, symName(tree, name)) case LabelDef(name, params, rhs) => print(symName(tree, name)); printLabelParams(params); printBlock(rhs) - case Import(expr, selectors) => - // Is this selector remapping a name (i.e, {name1 => name2}) - def isNotRemap(s: ImportSelector) : Boolean = (s.name == nme.WILDCARD || s.name == s.rename) - def selectorToString(s: ImportSelector): String = { - val from = quotedName(s.name) - if (isNotRemap(s)) from - else from + "=>" + quotedName(s.rename) - } - print("import ", backquotedPath(expr), ".") - selectors match { - case List(s) => - // If there is just one selector and it is not remapping a name, no braces are needed - if (isNotRemap(s)) print(selectorToString(s)) - else print("{", selectorToString(s), "}") - // If there is more than one selector braces are always needed - case many => - print(many.map(selectorToString).mkString("{", ", ", "}")) - } + case imp @ Import(expr, _) => + printImport(imp, backquotedPath(expr)) - case Template(parents, self, body) => + case Template(parents, self, body) => val currentOwner1 = currentOwner if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner -// if (parents exists isReferenceToAnyVal) { -// print("AnyVal") -// } -// else { printRow(parents, " with ") - if (!body.isEmpty) { + if (body.nonEmpty) { if (self.name != nme.WILDCARD) { print(" { ", self.name); printOpt(": ", self.tpt); print(" => ") - } else if (!self.tpt.isEmpty) { + } else if (self.tpt.nonEmpty) { print(" { _ : ", self.tpt, " => ") } else { print(" {") } printColumn(body, "", ";", "}") } -// } currentOwner = currentOwner1 case Block(stats, expr) => @@ -290,18 +357,8 @@ trait Printers extends api.Printers { self: SymbolTable => print(selector); printColumn(cases, " match {", "", "}") selectorType = selectorType1 - case CaseDef(pat, guard, body) => - print("case ") - def patConstr(pat: Tree): Tree = pat match { - case Apply(fn, args) => patConstr(fn) - case _ => pat - } - if (showOuterTests && - needsOuterTest( - patConstr(pat).tpe.finalResultType, selectorType, currentOwner)) - print("???") - print(pat); printOpt(" if ", guard) - print(" => ", body) + case cd @ CaseDef(pat, guard, body) => + printCaseDef(cd) case Alternative(trees) => printRow(trees, "(", "| ", ")") @@ -318,9 +375,8 @@ trait Printers extends api.Printers { self: SymbolTable => case ArrayValue(elemtpt, trees) => print("Array[", elemtpt); printRow(trees, "]{", ", ", "}") - case Function(vparams, body) => - print("("); printValueParams(vparams); print(" => ", body, ")") - if (printIds && tree.symbol != null) print("#"+tree.symbol.id) + case f @ Function(vparams, body) => + printFunction(f)(printValueParams(vparams)) case Assign(lhs, rhs) => print(lhs, " = ", rhs) @@ -331,7 +387,7 @@ trait Printers extends api.Printers { self: SymbolTable => case If(cond, thenp, elsep) => print("if (", cond, ")"); indent(); println() print(thenp); undent() - if (!elsep.isEmpty) { + if (elsep.nonEmpty) { println(); print("else"); indent(); println(); print(elsep); undent() } @@ -340,7 +396,7 @@ trait Printers extends api.Printers { self: SymbolTable => case Try(block, catches, finalizer) => print("try "); printBlock(block) - if (!catches.isEmpty) printColumn(catches, " catch {", "", "}") + if (catches.nonEmpty) printColumn(catches, " catch {", "", "}") printOpt(" finally ", finalizer) case Throw(expr) => @@ -362,22 +418,18 @@ trait Printers extends api.Printers { self: SymbolTable => print("<apply-dynamic>(", qual, "#", tree.symbol.nameString) printRow(vargs, ", (", ", ", "))") - case Super(This(qual), mix) => - if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".") - print("super") - if (!mix.isEmpty) - print("[" + mix + "]") + case st @ Super(This(qual), mix) => + printSuper(st, symName(tree, qual)) case Super(qual, mix) => print(qual, ".super") - if (!mix.isEmpty) + if (mix.nonEmpty) print("[" + mix + "]") - case This(qual) => - if (!qual.isEmpty) print(symName(tree, qual) + ".") - print("this") + case th @ This(qual) => + printThis(th, symName(tree, qual)) - case Select(qual @ New(tpe), name) if !settings.debug => + case Select(qual: New, name) if !settings.debug => print(qual) case Select(qualifier, name) => @@ -400,10 +452,10 @@ trait Printers extends api.Printers { self: SymbolTable => print(tree.tpe.toString) } - case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) => + case an @ Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) => def printAnnot() { print("@", tpt) - if (!args.isEmpty) + if (args.nonEmpty) printRow(args, "(", ",", ")") } print(tree, if (tree.isType) " " else ": ") @@ -435,11 +487,11 @@ trait Printers extends api.Printers { self: SymbolTable => print(tpt) printColumn(whereClauses, " forSome { ", ";", "}") -// SelectFromArray is no longer visible in scala.reflect.internal. -// eliminated until we figure out what we will do with both Printers and -// SelectFromArray. -// case SelectFromArray(qualifier, name, _) => -// print(qualifier); print(".<arr>"); print(symName(tree, name)) + // SelectFromArray is no longer visible in scala.reflect.internal. + // eliminated until we figure out what we will do with both Printers and + // SelectFromArray. + // case SelectFromArray(qualifier, name, _) => + // print(qualifier); print(".<arr>"); print(symName(tree, name)) case tree => xprintTree(this, tree) @@ -459,11 +511,498 @@ trait Printers extends api.Printers { self: SymbolTable => out.print(if (arg == null) "null" else arg.toString) } } + + // it's the printer for trees after parser and before typer phases + class ParsedTreePrinter(out: PrintWriter) extends TreePrinter(out) { + override def withTypes = this + override def withIds = this + override def withKinds = this + override def withMirrors = this + override def withPositions = this + + // TODO: add print parameters to typed trees printer + printTypes = false + printIds = false + printKinds = false + printMirrors = false + printPositions = false + + protected val parentsStack = scala.collection.mutable.Stack[Tree]() + + protected def currentTree = if (parentsStack.nonEmpty) Some(parentsStack.top) else None + + protected def currentParent = if (parentsStack.length > 1) Some(parentsStack(1)) else None + + protected def printedName(name: Name, decoded: Boolean = true) = { + import Chars._ + val decName = name.decoded + val bslash = '\\' + val brackets = List('[',']','(',')','{','}') + + def addBackquotes(s: String) = + if (decoded && (decName.exists(ch => brackets.contains(ch) || isWhitespace(ch)) || + (name.isOperatorName && decName.exists(isOperatorPart) && decName.exists(isScalaLetter) && !decName.contains(bslash)))) + s"`$s`" else s + + if (name == nme.CONSTRUCTOR) "this" + else addBackquotes(quotedName(name, decoded)) + } + + protected def isIntLitWithDecodedOp(qual: Tree, name: Name) = { + val qualIsIntLit = qual match { + case Literal(Constant(x: Int)) => true + case _ => false + } + qualIsIntLit && name.isOperatorName + } + + protected def needsParentheses(parent: Tree)(insideIf: Boolean = true, insideMatch: Boolean = true, + insideTry: Boolean = true, insideAnnotated: Boolean = true, insideBlock: Boolean = true, insideLabelDef: Boolean = true) = { + parent match { + case _: If => insideIf + case _: Match => insideMatch + case _: Try => insideTry + case _: Annotated => insideAnnotated + case _: Block => insideBlock + case _: LabelDef => insideLabelDef + case _ => false + } + } + + protected def checkForBlank(cond: Boolean) = if (cond) " " else "" + protected def blankForOperatorName(name: Name) = checkForBlank(name.isOperatorName) + protected def blankForName(name: Name) = checkForBlank(name.isOperatorName || name.endsWith("_")) + + protected def resolveSelect(t: Tree): String = { + t match { + // case for: 1) (if (a) b else c).meth1.meth2 or 2) 1 + 5 should be represented as (1).+(5) + case Select(qual, name) if (name.isTermName && needsParentheses(qual)(insideLabelDef = false)) || isIntLitWithDecodedOp(qual, name) => s"(${resolveSelect(qual)}).${printedName(name)}" + case Select(qual, name) if name.isTermName => s"${resolveSelect(qual)}.${printedName(name)}" + case Select(qual, name) if name.isTypeName => s"${resolveSelect(qual)}#${blankForOperatorName(name)}%${printedName(name)}" + case Ident(name) => printedName(name) + case _ => showCode(t) + } + } + + val defaultClasses = List(tpnme.AnyRef) + val defaultTraitsForCase = List(tpnme.Product, tpnme.Serializable) + protected def removeDefaultTypesFromList(trees: List[Tree])(classesToRemove: List[Name] = defaultClasses)(traitsToRemove: List[Name]) = { + def removeDefaultTraitsFromList(trees: List[Tree], traitsToRemove: List[Name]): List[Tree] = + trees match { + case Nil => trees + case init :+ last => last match { + case Select(Ident(sc), name) if traitsToRemove.contains(name) && sc == nme.scala_ => + removeDefaultTraitsFromList(init, traitsToRemove) + case _ => trees + } + } + + removeDefaultTraitsFromList(removeDefaultClassesFromList(trees, classesToRemove), traitsToRemove) + } + + protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) = trees filter { + case Select(Ident(sc), name) => !(classesToRemove.contains(name) && sc == nme.scala_) + case _ => true + } + + def printFlags(mods: Modifiers, primaryCtorParam: Boolean = false): Unit = { + val base = AccessFlags | OVERRIDE | ABSTRACT | FINAL | SEALED | LAZY + val mask = if (primaryCtorParam) base else base | IMPLICIT + + val s = mods.flagString(mask) + if (s != "") print(s"$s ") + // case flag should be the last + if (mods.isCase) print(mods.flagBitsToString(CASE) + " ") + if (mods.isAbstractOverride) print("abstract override ") + } + + override def printModifiers(tree: Tree, mods: Modifiers): Unit = printModifiers(mods, primaryCtorParam = false) + + def printModifiers(mods: Modifiers, primaryCtorParam: Boolean): Unit = { + def modsAccepted = List(currentTree, currentParent) exists (_ map { + case _: ClassDef | _: ModuleDef | _: Template | _: PackageDef => true + case _ => false + } getOrElse false) + + if (currentParent.isEmpty || modsAccepted) + printFlags(mods, primaryCtorParam) + else + List(IMPLICIT, CASE, LAZY, SEALED).foreach{flag => if (mods.hasFlag(flag)) print(s"${mods.flagBitsToString(flag)} ")} + } + + def printParam(tree: Tree, primaryCtorParam: Boolean): Unit = + tree match { + case vd @ ValDef(mods, name, tp, rhs) => + printAnnotations(vd) + val mutableOrOverride = mods.isOverride || mods.isMutable + val hideCtorMods = mods.isParamAccessor && mods.isPrivateLocal && !mutableOrOverride + val hideCaseCtorMods = mods.isCaseAccessor && mods.isPublic && !mutableOrOverride + + if (primaryCtorParam && !(hideCtorMods || hideCaseCtorMods)) { + printModifiers(mods, primaryCtorParam) + print(if (mods.isMutable) "var " else "val "); + } + print(printedName(name), blankForName(name)); + printOpt(": ", tp); + printOpt(" = ", rhs) + case TypeDef(_, name, tparams, rhs) => + print(printedName(name)) + printTypeParams(tparams); + print(rhs) + case _ => + super.printParam(tree) + } + + override def printParam(tree: Tree): Unit = { + printParam(tree, primaryCtorParam = false) + } + + protected def printArgss(argss: List[List[Tree]]) = + argss foreach {x: List[Tree] => if (!(x.isEmpty && argss.size == 1)) printRow(x, "(", ", ", ")")} + + override def printAnnotations(tree: MemberDef) = { + val annots = tree.mods.annotations + annots foreach {annot => printAnnot(annot); print(" ")} + } + + protected def printAnnot(tree: Tree) = { + tree match { + case treeInfo.Applied(core, _, argss) => + print("@") + core match { + case Select(New(tree), _) => print(tree) + case _ => + } + printArgss(argss) + case _ => super.printTree(tree) + } + } + + override def printTree(tree: Tree): Unit = { + parentsStack.push(tree) + tree match { + case cl @ ClassDef(mods, name, tparams, impl) => + if (mods.isJavaDefined) super.printTree(cl) + printAnnotations(cl) + // traits + val clParents: List[Tree] = if (mods.isTrait) { + // avoid abstract modifier for traits + printModifiers(tree, mods &~ ABSTRACT) + print("trait ", printedName(name)) + printTypeParams(tparams) + + val build.SyntacticTraitDef(_, _, _, _, parents, _, _) = tree + parents + // classes + } else { + printModifiers(tree, mods) + print("class ", printedName(name)) + printTypeParams(tparams) + + val build.SyntacticClassDef(_, _, _, ctorMods, vparamss, earlyDefs, parents, selfType, body) = cl + + // constructor's modifier + if (ctorMods.hasFlag(AccessFlags)) { + print(" ") + printModifiers(ctorMods, primaryCtorParam = false) + } + + def printConstrParams(ts: List[ValDef]): Unit = { + parenthesize() { + printImplicitInParamsList(ts) + printSeq(ts)(printParam(_, primaryCtorParam = true))(print(", ")) + } + } + // constructor's params processing (don't print single empty constructor param list) + vparamss match { + case Nil | List(Nil) if (!mods.isCase && !ctorMods.hasFlag(AccessFlags)) => + case _ => vparamss foreach printConstrParams + } + parents + } + + // get trees without default classes and traits (when they are last) + val printedParents = removeDefaultTypesFromList(clParents)()(if (mods.hasFlag(CASE)) defaultTraitsForCase else Nil) + print(if (mods.isDeferred) "<: " else if (printedParents.nonEmpty) " extends " else "", impl) + + case pd @ PackageDef(packaged, stats) => + packaged match { + case Ident(name) if name == nme.EMPTY_PACKAGE_NAME => + printSeq(stats) { + print(_) + } { + print(";"); + println() + }; + case _ => + val separator = scala.util.Properties.lineSeparator + printPackageDef(pd, separator) + } + + case md @ ModuleDef(mods, name, impl) => + printAnnotations(md) + printModifiers(tree, mods) + val Template(parents, self, methods) = impl + val parWithoutAnyRef = removeDefaultClassesFromList(parents) + print("object " + printedName(name), if (parWithoutAnyRef.nonEmpty) " extends " else "", impl) + + case vd @ ValDef(mods, name, tp, rhs) => + printValDef(vd, printedName(name)) { + // place space after symbolic def name (val *: Unit does not compile) + printOpt(s"${blankForName(name)}: ", tp) + } { + if (!mods.isDeferred) print(" = ", if (rhs.isEmpty) "_" else rhs) + } + + case dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) => + printDefDef(dd, printedName(name)) { + if (tparams.isEmpty && (vparamss.isEmpty || vparamss(0).isEmpty)) print(blankForName(name)) + printOpt(": ", tp) + } { + printOpt(" = " + (if (mods.isMacro) "macro " else ""), rhs) + } + + case td @ TypeDef(mods, name, tparams, rhs) => + printTypeDef(td, printedName(name)) + + case LabelDef(name, params, rhs) => + if (name.startsWith(nme.WHILE_PREFIX)) { + val If(cond, thenp, elsep) = rhs + print("while (", cond, ") ") + val Block(list, wh) = thenp + printColumn(list, "", ";", "") + } else if (name.startsWith(nme.DO_WHILE_PREFIX)) { + val Block(bodyList, ifCond @ If(cond, thenp, elsep)) = rhs + print("do ") + printColumn(bodyList, "", ";", "") + print(" while (", cond, ") ") + } else { + print(printedName(name)); printLabelParams(params); + printBlock(rhs) + } + + case imp @ Import(expr, _) => + printImport(imp, resolveSelect(expr)) + + case Template(parents, self, body) => + val printedParents = + currentParent map { + case _: CompoundTypeTree => parents + case ClassDef(mods, name, _, _) if mods.isCase => removeDefaultTypesFromList(parents)()(List(tpnme.Product, tpnme.Serializable)) + case _ => removeDefaultClassesFromList(parents) + } getOrElse (parents) + + val primaryCtr = treeInfo.firstConstructor(body) + val ap: Option[Apply] = primaryCtr match { + case DefDef(_, _, _, _, _, Block(ctBody, _)) => + val earlyDefs = treeInfo.preSuperFields(ctBody) ::: body.filter { + case td: TypeDef => treeInfo.isEarlyDef(td) + case _ => false + } + if (earlyDefs.nonEmpty) { + print("{") + printColumn(earlyDefs, "", ";", "") + print("} " + (if (printedParents.nonEmpty) "with " else "")) + } + ctBody collectFirst { + case apply: Apply => apply + } + case _ => None + } + + if (printedParents.nonEmpty) { + val (clParent :: traits) = printedParents + print(clParent) + + val constrArgss = ap match { + case Some(treeInfo.Applied(_, _, argss)) => argss + case _ => Nil + } + printArgss(constrArgss) + if (traits.nonEmpty) { + printRow(traits, " with ", " with ", "") + } + } + /* Remove primary constr def and constr val and var defs + * right contains all constructors + */ + val (left, right) = body.filter { + // remove valdefs defined in constructor and presuper vals + case vd: ValDef => !vd.mods.isParamAccessor && !treeInfo.isEarlyValDef(vd) + // remove $this$ from traits + case dd: DefDef => dd.name != nme.MIXIN_CONSTRUCTOR + case td: TypeDef => !treeInfo.isEarlyDef(td) + case EmptyTree => false + case _ => true + } span { + case dd: DefDef => dd.name != nme.CONSTRUCTOR + case _ => true + } + val modBody = left ::: right.drop(1) + val showBody = !(modBody.isEmpty && (self == noSelfType || self.isEmpty)) + if (showBody) { + if (self.name != nme.WILDCARD) { + print(" { ", self.name); + printOpt(": ", self.tpt); + print(" =>") + } else if (self.tpt.nonEmpty) { + print(" { _ : ", self.tpt, " =>") + } else { + print(" {") + } + printColumn(modBody, "", ";", "}") + } + + case Block(stats, expr) => super.printTree(tree) + + case Match(selector, cases) => + /* Insert braces if match is inner + * make this function available for other cases + * passing required type for checking + */ + def insertBraces(body: => Unit): Unit = + if (parentsStack.nonEmpty && parentsStack.tail.exists(_.isInstanceOf[Match])) { + print("(") + body + print(")") + } else body + + val printParentheses = needsParentheses(selector)(insideLabelDef = false) + tree match { + case Match(EmptyTree, cs) => + printColumn(cases, "{", "", "}") + case _ => + insertBraces { + parenthesize(printParentheses)(print(selector)) + printColumn(cases, " match {", "", "}") + } + } + + case cd @ CaseDef(pat, guard, body) => + printCaseDef(cd) + + case Star(elem) => + print(elem, "*") + + case Bind(name, t) => + if (t == EmptyTree) print("(", printedName(name), ")") + else if (t.exists(_.isInstanceOf[Star])) print(printedName(name), " @ ", t) + else print("(", printedName(name), " @ ", t, ")") + + case f @ Function(vparams, body) => + // parentheses are not allowed for val a: Int => Int = implicit x => x + val printParentheses = vparams match { + case head :: _ => !head.mods.isImplicit + case _ => true + } + printFunction(f)(printValueParams(vparams, inParentheses = printParentheses)) + + case Typed(expr, tp) => + tp match { + case Function(List(), EmptyTree) => print("(", expr, " _)") //func _ + // parentheses required when (a match {}) : Type + case _ => print("((", expr, "): ", tp, ")") + } + + case Apply(fun, vargs) => + tree match { + // processing methods ending on colons (x \: list) + case Apply(Block(l1 @ List(sVD: ValDef), a1 @ Apply(Select(_, methodName), l2 @ List(Ident(iVDName)))), l3) + if sVD.mods.isSynthetic && treeInfo.isLeftAssoc(methodName) && sVD.name == iVDName => + val printBlock = Block(l1, Apply(a1, l3)) + print(printBlock) + case Apply(tree1, _) if (needsParentheses(tree1)(insideAnnotated = false)) => + parenthesize()(print(fun)); printRow(vargs, "(", ", ", ")") + case _ => super.printTree(tree) + } + + case st @ Super(This(qual), mix) => + printSuper(st, printedName(qual)) + + case th @ This(qual) => + printThis(th, printedName(qual)) + + case Select(qual: New, name) => + print(qual) + + case Select(qualifier, name) => { + val printParentheses = needsParentheses(qualifier)(insideAnnotated = false) || isIntLitWithDecodedOp(qualifier, name) + if (printParentheses) print("(", resolveSelect(qualifier), ").", printedName(name)) + else print(resolveSelect(qualifier), ".", printedName(name)) + } + + case id @ Ident(name) => + if (name.nonEmpty) { + if (name == nme.dollarScope) { + print(s"scala.xml.${nme.TopScope}") + } else { + val str = printedName(name) + val strIsBackquoted = str.startsWith("`") && str.endsWith("`") + print(if (id.isBackquoted && !strIsBackquoted) "`" + str + "`" else str) + } + } else { + print("") + } + + case l @ Literal(x) => + import Chars.LF + x match { + case Constant(v: String) if { + val strValue = x.stringValue + strValue.contains(LF) && strValue.contains("\"\"\"") && strValue.size > 1 + } => + val splitValue = x.stringValue.split(s"$LF").toList + val multilineStringValue = if (x.stringValue.endsWith(s"$LF")) splitValue :+ "" else splitValue + val trQuotes = "\"\"\"" + print(trQuotes); printSeq(multilineStringValue) { print(_) } { print(LF) }; print(trQuotes) + case _ => + // processing Float constants + val printValue = x.escapedStringValue + (if (x.value.isInstanceOf[Float]) "F" else "") + print(printValue) + } + + case an @ Annotated(ap, tree) => + val printParentheses = needsParentheses(tree)() + parenthesize(printParentheses) { print(tree) }; print(if (tree.isType) " " else ": ") + printAnnot(ap) + + case SelectFromTypeTree(qualifier, selector) => + print("(", qualifier, ")#", blankForOperatorName(selector), printedName(selector)) + + case AppliedTypeTree(tp, args) => + // it's possible to have (=> String) => String type but Function1[=> String, String] is not correct + val containsByNameTypeParam = args exists treeInfo.isByNameParamType + + if (containsByNameTypeParam) { + print("(") + printRow(args.init, "(", ", ", ")") + print(" => ", args.last, ")") + } else { + if (treeInfo.isRepeatedParamType(tree) && args.nonEmpty) { + print(args(0), "*") + } else if (treeInfo.isByNameParamType(tree)) { + print("=> ", if (args.isEmpty) "()" else args(0)) + } else + super.printTree(tree) + } + + case ExistentialTypeTree(tpt, whereClauses) => + print("(", tpt); + printColumn(whereClauses, " forSome { ", ";", "})") + + case EmptyTree => + + case tree => super.printTree(tree) + } + parentsStack.pop() + } + } /** Hook for extensions */ def xprintTree(treePrinter: TreePrinter, tree: Tree) = treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")")) + def newCodePrinter(writer: PrintWriter): TreePrinter = new ParsedTreePrinter(writer) def newTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer) def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream)) def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter)) diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala index b7a1681838..cf3f356daa 100644 --- a/src/reflect/scala/reflect/internal/Scopes.scala +++ b/src/reflect/scala/reflect/internal/Scopes.scala @@ -387,7 +387,7 @@ trait Scopes extends api.Scopes { self: SymbolTable => if (toList forall p) this else newScopeWith(toList filter p: _*) ) - @deprecated("Use `toList.reverse` instead", "2.10.0") + @deprecated("Use `toList.reverse` instead", "2.10.0") // Used in SBT 0.12.4 def reverse: List[Symbol] = toList.reverse override def mkString(start: String, sep: String, end: String) = diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index ea6afa7349..ed3e7dbc4c 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -686,6 +686,7 @@ trait StdNames { val inlinedEquals: NameType = "inlinedEquals" val isArray: NameType = "isArray" val isDefinedAt: NameType = "isDefinedAt" + val isEmpty: NameType = "isEmpty" val isInstanceOf_ : NameType = "isInstanceOf" val isInstanceOf_Ob : NameType = "$isInstanceOf" val java: NameType = "java" @@ -762,8 +763,8 @@ trait StdNames { val unapplySeq: NameType = "unapplySeq" val unbox: NameType = "unbox" val universe: NameType = "universe" - val UnliftHelper1: NameType = "UnliftHelper1" - val UnliftHelper2: NameType = "UnliftHelper2" + val UnliftListElementwise: NameType = "UnliftListElementwise" + val UnliftListOfListsElementwise: NameType = "UnliftListOfListsElementwise" val update: NameType = "update" val updateDynamic: NameType = "updateDynamic" val value: NameType = "value" diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index c46a559d6d..571c4cfa5d 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -65,9 +65,6 @@ abstract class SymbolTable extends macros.Universe def isPastTyper = false protected def isDeveloper: Boolean = settings.debug - @deprecated("Give us a reason", "2.10.0") - def abort(): Nothing = abort("unknown error") - @deprecated("Use devWarning if this is really a warning; otherwise use log", "2.11.0") def debugwarn(msg: => String): Unit = devWarning(msg) @@ -356,16 +353,18 @@ abstract class SymbolTable extends macros.Universe // Weak references so the garbage collector will take care of // letting us know when a cache is really out of commission. - private val caches = WeakHashSet[Clearable]() + import java.lang.ref.WeakReference + private var caches = List[WeakReference[Clearable]]() def recordCache[T <: Clearable](cache: T): T = { - caches += cache + caches ::= new WeakReference(cache) cache } def clearAll() = { debuglog("Clearing " + caches.size + " caches.") - caches foreach (_.clear) + caches foreach (ref => Option(ref.get).foreach(_.clear)) + caches = caches.filterNot(_.get == null) } def newWeakMap[K, V]() = recordCache(mutable.WeakHashMap[K, V]()) @@ -376,9 +375,9 @@ abstract class SymbolTable extends macros.Universe val NoCached: T = null.asInstanceOf[T] var cached: T = NoCached var cachedRunId = NoRunId - caches += new Clearable { + recordCache(new Clearable { def clear(): Unit = cached = NoCached - } + }) () => { if (currentRunId != cachedRunId || cached == NoCached) { cached = f @@ -403,10 +402,9 @@ abstract class SymbolTable extends macros.Universe */ def isCompilerUniverse = false - @deprecated("Use enteringPhase", "2.10.0") + @deprecated("Use enteringPhase", "2.10.0") // Used in SBT 0.12.4 @inline final def atPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph)(op) - @deprecated("Use enteringPhaseNotLaterThan", "2.10.0") - @inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T = enteringPhaseNotLaterThan(target)(op) + /** * Adds the `sm` String interpolator to a [[scala.StringContext]]. diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index e15b33e5d7..f49ddaf6ca 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -2419,7 +2419,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (isTrait) ("trait", "trait", "TRT") else if (isClass) ("class", "class", "CLS") else if (isType) ("type", "type", "TPE") - else if (isClassConstructor && isPrimaryConstructor) ("primary constructor", "constructor", "PCTOR") + else if (isClassConstructor && (owner.hasCompleteInfo && isPrimaryConstructor)) ("primary constructor", "constructor", "PCTOR") else if (isClassConstructor) ("constructor", "constructor", "CTOR") else if (isSourceMethod) ("method", "method", "METH") else if (isTerm) ("value", "value", "VAL") @@ -2519,6 +2519,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (settings.debug.value) parentsString(tp.parents) else briefParentsString(tp.parents) ) + def isStructuralThisType = ( + // prevents disasters like SI-8158 + owner.isInitialized && owner.isStructuralRefinement && tp == owner.tpe + ) if (isType) typeParamsString(tp) + ( if (isClass) " extends " + parents else if (isAliasType) " = " + tp.resultType @@ -2529,10 +2533,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => ) else if (isModule) "" // avoid "object X of type X.type" else tp match { - case PolyType(tparams, res) => typeParamsString(tp) + infoString(res) - case NullaryMethodType(res) => infoString(res) - case MethodType(params, res) => valueParamsString(tp) + infoString(res) - case _ => ": " + tp + case PolyType(tparams, res) => typeParamsString(tp) + infoString(res) + case NullaryMethodType(res) => infoString(res) + case MethodType(params, res) => valueParamsString(tp) + infoString(res) + case _ if isStructuralThisType => ": " + owner.name + case _ => ": " + tp } } diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index f6d21ec9bd..b16cbd8325 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -95,7 +95,7 @@ abstract class TreeGen extends macros.TreeBuilder { case ConstantType(value) => Literal(value) setType tpe - case AnnotatedType(_, atp, _) => + case AnnotatedType(_, atp) => mkAttributedQualifier(atp) case RefinedType(parents, _) => @@ -191,11 +191,7 @@ abstract class TreeGen extends macros.TreeBuilder { ) val pkgQualifier = if (needsPackageQualifier) { - // The owner of a symbol which requires package qualification may be the - // package object iself, but it also could be any superclass of the package - // object. In the latter case, we must go through the qualifier's info - // to obtain the right symbol. - val packageObject = if (sym.owner.isModuleClass) sym.owner.sourceModule else qual.tpe member nme.PACKAGE + val packageObject = rootMirror.getPackageObjectWithMember(qual.tpe, sym) Select(qual, nme.PACKAGE) setSymbol packageObject setType singleType(qual.tpe, packageObject) } else qual diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 8fdf4dc27a..497a7c91b1 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -612,8 +612,8 @@ abstract class TreeInfo { def effectivePatternArity(args: List[Tree]): Int = flattenedPatternArgs(args).length def flattenedPatternArgs(args: List[Tree]): List[Tree] = args map unbind match { - case Apply(fun, xs) :: Nil if isTupleSymbol(fun.symbol) => xs - case xs => xs + case build.SyntacticTuple(xs) :: Nil => xs + case xs => xs } // used in the symbols for labeldefs and valdefs emitted by the pattern matcher diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 45daa2ae04..9ddaea4c62 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -8,7 +8,6 @@ package reflect package internal import scala.collection.{ mutable, immutable, generic } -import generic.Clearable import scala.ref.WeakReference import mutable.ListBuffer import Flags._ @@ -44,7 +43,7 @@ import TypeConstants._ // parent1 with ... with parentn { defs } case ExistentialType(tparams, result) => // result forSome { tparams } - case AnnotatedType(annots, tp, selfsym) => + case AnnotatedType(annots, tp) => // tp @annots // the following are non-value types; you cannot write them down in Scala source. @@ -895,7 +894,7 @@ trait Types if (sym == btssym) return mid else if (sym isLess btssym) hi = mid - 1 else if (btssym isLess sym) lo = mid + 1 - else abort() + else abort("sym is neither `sym == btssym`, `sym isLess btssym` nor `btssym isLess sym`") } -1 } @@ -1191,13 +1190,6 @@ trait Types def setAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this) def withAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this) - /** Set the self symbol of an annotated type, or do nothing - * otherwise. */ - def withSelfsym(sym: Symbol) = this - - /** The selfsym of an annotated type, or NoSymbol of anything else */ - def selfsym: Symbol = NoSymbol - /** The kind of this type; used for debugging */ def kind: String = "unknown type of class "+getClass() } @@ -1457,7 +1449,7 @@ trait Types override def safeToString = scalaNotation(_.toString) - /** Bounds notation used in Scala sytanx. + /** Bounds notation used in Scala syntax. * For example +This <: scala.collection.generic.Sorted[K,This]. */ private[internal] def scalaNotation(typeString: Type => String): String = { @@ -1999,7 +1991,9 @@ trait Types if (sym.typeParams.size != args.size) devWarning(s"$this.transform($tp), but tparams.isEmpty and args=$args") - asSeenFromOwner(tp).instantiateTypeParams(sym.typeParams, args) + val GenPolyType(tparams, result) = asSeenFromOwner(tp) + assert((tparams eq Nil) || tparams == sym.typeParams, (tparams, sym.typeParams)) + result.instantiateTypeParams(sym.typeParams, args) } // note: does not go through typeRef. There's no need to because @@ -2309,7 +2303,14 @@ trait Types } thisInfo.decls } - protected[Types] def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform + protected[Types] def baseTypeSeqImpl: BaseTypeSeq = + if (sym.info.baseTypeSeq exists (_.typeSymbolDirect.isAbstractType)) + // SI-8046 base type sequence might have more elements in a subclass, we can't map it element wise. + transform(sym.info).baseTypeSeq + else + // Optimization: no abstract types, we can compute the BTS of this TypeRef as an element-wise map + // of the BTS of the referenced symbol. + sym.info.baseTypeSeq map transform override def baseTypeSeq: BaseTypeSeq = { val cache = baseTypeSeqCache @@ -3239,13 +3240,9 @@ trait Types * * @param annotations the list of annotations on the type * @param underlying the type without the annotation - * @param selfsym a "self" symbol with type `underlying`; - * only available if -Yself-in-annots is turned on. Can be `NoSymbol` - * if it is not used. */ case class AnnotatedType(override val annotations: List[AnnotationInfo], - override val underlying: Type, - override val selfsym: Symbol) + override val underlying: Type) extends RewrappingTypeProxy with AnnotatedTypeApi { assert(!annotations.isEmpty, "" + underlying) @@ -3278,9 +3275,6 @@ trait Types */ override def withoutAnnotations = underlying.withoutAnnotations - /** Set the self symbol */ - override def withSelfsym(sym: Symbol) = copy(selfsym = sym) - /** Drop the annotations on the bounds, unless the low and high * bounds are exactly tp. */ @@ -3295,7 +3289,7 @@ trait Types formals, actuals), info.args, info.assocs).setPos(info.pos)) val underlying1 = underlying.instantiateTypeParams(formals, actuals) if ((annotations1 eq annotations) && (underlying1 eq underlying)) this - else AnnotatedType(annotations1, underlying1, selfsym) + else AnnotatedType(annotations1, underlying1) } /** Return the base type sequence of tp, dropping the annotations, unless the base type sequence of tp @@ -3314,9 +3308,9 @@ trait Types /** Creator for AnnotatedTypes. It returns the underlying type if annotations.isEmpty * rather than walking into the assertion. */ - def annotatedType(annots: List[AnnotationInfo], underlying: Type, selfsym: Symbol = NoSymbol): Type = + def annotatedType(annots: List[AnnotationInfo], underlying: Type): Type = if (annots.isEmpty) underlying - else AnnotatedType(annots, underlying, selfsym) + else AnnotatedType(annots, underlying) object AnnotatedType extends AnnotatedTypeExtractor @@ -3569,7 +3563,7 @@ trait Types case RefinedType(parents, decls) => RefinedType(parents map (appliedType(_, args)), decls) // @PP: Can this be right? case TypeBounds(lo, hi) => TypeBounds(appliedType(lo, args), appliedType(hi, args)) // @PP: Can this be right? case tv@TypeVar(_, _) => tv.applyArgs(args) - case AnnotatedType(annots, underlying, self) => AnnotatedType(annots, appliedType(underlying, args), self) + case AnnotatedType(annots, underlying) => AnnotatedType(annots, appliedType(underlying, args)) case ErrorType | WildcardType => tycon case _ => abort(debugString(tycon)) } @@ -3605,7 +3599,7 @@ trait Types } def genPolyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe) - @deprecated("use genPolyType(...) instead", "2.10.0") + @deprecated("use genPolyType(...) instead", "2.10.0") // Used in reflection API def polyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe) /** A creator for anonymous type functions, where the symbol for the type function still needs to be created. @@ -3664,7 +3658,11 @@ trait Types if (Statistics.canEnable) Statistics.incCounter(rawTypeCount) if (uniqueRunId != currentRunId) { uniques = util.WeakHashSet[Type](initialUniquesCapacity) - perRunCaches.recordCache(uniques) + // JZ: We used to register this as a perRunCache so it would be cleared eagerly at + // the end of the compilation run. But, that facility didn't actually clear this map (SI-8129)! + // When i fixed that bug, run/tpeCache-tyconCache.scala started failing. Why was that? + // I've removed the registration for now. I don't think its particularly harmful anymore + // as a) this is now a weak set, and b) it is discarded completely before the next run. uniqueRunId = currentRunId } (uniques findEntryOrUpdate tp).asInstanceOf[T] @@ -3674,7 +3672,7 @@ trait Types class TypeUnwrapper(poly: Boolean, existential: Boolean, annotated: Boolean, nullary: Boolean) extends (Type => Type) { def apply(tp: Type): Type = tp match { - case AnnotatedType(_, underlying, _) if annotated => apply(underlying) + case AnnotatedType(_, underlying) if annotated => apply(underlying) case ExistentialType(_, underlying) if existential => apply(underlying) case PolyType(_, underlying) if poly => apply(underlying) case NullaryMethodType(underlying) if nullary => apply(underlying) @@ -3717,7 +3715,7 @@ trait Types def transparentShallowTransform(container: Symbol, tp: Type)(f: Type => Type): Type = { def loop(tp: Type): Type = tp match { - case tp @ AnnotatedType(_, underlying, _) => tp.copy(underlying = loop(underlying)) + case tp @ AnnotatedType(_, underlying) => tp.copy(underlying = loop(underlying)) case tp @ ExistentialType(_, underlying) => tp.copy(underlying = loop(underlying)) case tp @ PolyType(_, resultType) => tp.copy(resultType = loop(resultType)) case tp @ NullaryMethodType(resultType) => tp.copy(resultType = loop(resultType)) @@ -4078,7 +4076,7 @@ trait Types private def isValueElseNonValue(tp: Type): Boolean = tp match { case tp if isAlwaysValueType(tp) => true case tp if isAlwaysNonValueType(tp) => false - case AnnotatedType(_, underlying, _) => isValueElseNonValue(underlying) + case AnnotatedType(_, underlying) => isValueElseNonValue(underlying) case SingleType(_, sym) => sym.isValue // excludes packages and statics case TypeRef(_, _, _) if tp.isHigherKinded => false // excludes type constructors case ThisType(sym) => !sym.isPackageClass // excludes packages diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index cd09e83cd3..a7cac5254c 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -84,7 +84,7 @@ trait Variances { loop(base, Covariant) } def isUncheckedVariance(tp: Type) = tp match { - case AnnotatedType(annots, _, _) => annots exists (_ matches definitions.uncheckedVarianceClass) + case AnnotatedType(annots, _) => annots exists (_ matches definitions.uncheckedVarianceClass) case _ => false } @@ -202,7 +202,7 @@ trait Variances { case MethodType(params, restpe) => inSyms(params).flip & inType(restpe) case PolyType(tparams, restpe) => inSyms(tparams).flip & inType(restpe) case ExistentialType(tparams, restpe) => inSyms(tparams) & inType(restpe) - case AnnotatedType(annots, tp, _) => inTypes(annots map (_.atp)) & inType(tp) + case AnnotatedType(annots, tp) => inTypes(annots map (_.atp)) & inType(tp) } inType(tp) diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 3d222fce10..2a19441476 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -362,7 +362,7 @@ abstract class UnPickler { case METHODtpe => MethodTypeRef(readTypeRef(), readSymbols()) case POLYtpe => PolyOrNullaryType(readTypeRef(), readSymbols()) case EXISTENTIALtpe => ExistentialType(underlying = readTypeRef(), quantified = readSymbols()) - case ANNOTATEDtpe => AnnotatedType(underlying = readTypeRef(), annotations = readAnnots(), selfsym = NoSymbol) + case ANNOTATEDtpe => AnnotatedType(underlying = readTypeRef(), annotations = readAnnots()) } } diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala index 6b33aca025..1c4d05ae32 100644 --- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala +++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala @@ -316,7 +316,7 @@ private[internal] trait GlbLubs { NullaryMethodType(lub0(matchingRestypes(ts, Nil))) case ts @ TypeBounds(_, _) :: rest => TypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth)) - case ts @ AnnotatedType(annots, tpe, _) :: rest => + case ts @ AnnotatedType(annots, tpe) :: rest => annotationsLub(lub0(ts map (_.withoutAnnotations)), ts) case ts => lubResults get ((depth, ts)) match { diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index b60fecd66e..3c4e93f11d 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -17,20 +17,15 @@ trait TypeComparers { private val _pendingSubTypes = new mutable.HashSet[SubTypePair] def pendingSubTypes = _pendingSubTypes - class SubTypePair(val tp1: Type, val tp2: Type) { - override def hashCode = tp1.hashCode * 41 + tp2.hashCode - override def equals(other: Any) = (this eq other.asInstanceOf[AnyRef]) || (other match { - // suspend TypeVars in types compared by =:=, - // since we don't want to mutate them simply to check whether a subtype test is pending - // in addition to making subtyping "more correct" for type vars, - // it should avoid the stackoverflow that's been plaguing us (https://groups.google.com/d/topic/scala-internals/2gHzNjtB4xA/discussion) - // this method is only called when subtyping hits a recursion threshold (subsametypeRecursions >= LogPendingSubTypesThreshold) - case stp: SubTypePair => - val tvars = List(tp1, stp.tp1, tp2, stp.tp2) flatMap (t => if (t.isGround) Nil else typeVarsInType(t)) - suspendingTypeVars(tvars)(tp1 =:= stp.tp1 && tp2 =:= stp.tp2) - case _ => - false - }) + final case class SubTypePair(tp1: Type, tp2: Type) { + // SI-8146 we used to implement equality here in terms of pairwise =:=. + // But, this was inconsistent with hashCode, which was based on the + // Type#hashCode, based on the structure of types, not the meaning. + // Now, we use `Type#{equals,hashCode}` as the (consistent) basis for + // detecting cycles (aka keeping subtyping decidable.) + // + // I added a tests to show that we detect the cycle: neg/t8146-no-finitary* + override def toString = tp1+" <:<? "+tp2 } @@ -170,11 +165,20 @@ trait TypeComparers { // corresponds does not check length of two sequences before checking the predicate, // but SubstMap assumes it has been checked (SI-2956) ( sameLength(tparams1, tparams2) - && (tparams1 corresponds tparams2)((p1, p2) => p1.info =:= subst(p2.info)) + && (tparams1 corresponds tparams2)((p1, p2) => methodHigherOrderTypeParamsSameVariance(p1, p2) && p1.info =:= subst(p2.info)) && (res1 =:= subst(res2)) ) } + // SI-2066 This prevents overrides with incompatible variance in higher order type parameters. + private def methodHigherOrderTypeParamsSameVariance(sym1: Symbol, sym2: Symbol) = { + def ignoreVariance(sym: Symbol) = !(sym.isHigherOrderTypeParameter && sym.logicallyEnclosingMember.isMethod) + ignoreVariance(sym1) || ignoreVariance(sym2) || sym1.variance == sym2.variance + } + + private def methodHigherOrderTypeParamsSubVariance(low: Symbol, high: Symbol) = + methodHigherOrderTypeParamsSameVariance(low, high) || low.variance.isInvariant + def isSameType2(tp1: Type, tp2: Type): Boolean = { def retry(lhs: Type, rhs: Type) = ((lhs ne tp1) || (rhs ne tp2)) && isSameType(lhs, rhs) @@ -262,7 +266,7 @@ trait TypeComparers { if (subsametypeRecursions >= LogPendingSubTypesThreshold) { val p = new SubTypePair(tp1, tp2) if (pendingSubTypes(p)) - false + false // see neg/t8146-no-finitary* else try { pendingSubTypes += p @@ -327,7 +331,10 @@ trait TypeComparers { val substitutes = if (isMethod) tparams1 else cloneSymbols(tparams1) def sub1(tp: Type) = if (isMethod) tp else tp.substSym(tparams1, substitutes) def sub2(tp: Type) = tp.substSym(tparams2, substitutes) - def cmp(p1: Symbol, p2: Symbol) = sub2(p2.info) <:< sub1(p1.info) + def cmp(p1: Symbol, p2: Symbol) = ( + methodHigherOrderTypeParamsSubVariance(p2, p1) + && sub2(p2.info) <:< sub1(p1.info) + ) (tparams1 corresponds tparams2)(cmp) && (sub1(res1) <:< sub2(res2)) } @@ -403,14 +410,14 @@ trait TypeComparers { case _ => secondTry } - case AnnotatedType(_, _, _) => + case AnnotatedType(_, _) => isSubType(tp1.withoutAnnotations, tp2.withoutAnnotations, depth) && annotationsConform(tp1, tp2) case BoundedWildcardType(bounds) => isSubType(tp1, bounds.hi, depth) case tv2 @ TypeVar(_, constr2) => tp1 match { - case AnnotatedType(_, _, _) | BoundedWildcardType(_) => + case AnnotatedType(_, _) | BoundedWildcardType(_) => secondTry case _ => tv2.registerBound(tp1, isLowerBound = true) @@ -425,7 +432,7 @@ trait TypeComparers { * - handle existential types by skolemization. */ def secondTry = tp1 match { - case AnnotatedType(_, _, _) => + case AnnotatedType(_, _) => isSubType(tp1.withoutAnnotations, tp2.withoutAnnotations, depth) && annotationsConform(tp1, tp2) case BoundedWildcardType(bounds) => diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index f5aa048e6a..09f4389b82 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -48,7 +48,7 @@ private[internal] trait TypeMaps { case TypeRef(_, sym, _) if sym.isAliasType => apply(tp.dealias) case TypeRef(_, sym, _) if sym.isAbstractType => apply(tp.bounds.hi) case rtp @ RefinedType(parents, decls) => copyRefinedType(rtp, parents mapConserve this, decls) - case AnnotatedType(_, _, _) => mapOver(tp) + case AnnotatedType(_, _) => mapOver(tp) case _ => tp // no recursion - top level only } } @@ -174,12 +174,12 @@ private[internal] trait TypeMaps { case tv@TypeVar(_, constr) => if (constr.instValid) this(constr.inst) else tv.applyArgs(mapOverArgs(tv.typeArgs, tv.params)) //@M !args.isEmpty implies !typeParams.isEmpty - case AnnotatedType(annots, atp, selfsym) => + case AnnotatedType(annots, atp) => val annots1 = mapOverAnnotations(annots) val atp1 = this(atp) if ((annots1 eq annots) && (atp1 eq atp)) tp else if (annots1.isEmpty) atp1 - else AnnotatedType(annots1, atp1, selfsym) + else AnnotatedType(annots1, atp1) /* case ErrorType => tp case WildcardType => tp @@ -1142,7 +1142,7 @@ private[internal] trait TypeMaps { case SuperType(_, _) => mapOver(tp) case TypeBounds(_, _) => mapOver(tp) case TypeVar(_, _) => mapOver(tp) - case AnnotatedType(_,_,_) => mapOver(tp) + case AnnotatedType(_, _) => mapOver(tp) case ExistentialType(_, _) => mapOver(tp) case _ => tp } diff --git a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala index ebc4394d25..a062fc8209 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala @@ -3,19 +3,29 @@ package reflect package internal package tpe +import scala.collection.mutable.HashSet + private[internal] trait TypeToStrings { self: SymbolTable => /** The maximum number of recursions allowed in toString */ - final val maxTostringRecursions = 50 + final val maxToStringRecursions = 50 + + private var _toStringRecursions = 0 + def toStringRecursions = _toStringRecursions + def toStringRecursions_=(value: Int) = _toStringRecursions = value - private var _tostringRecursions = 0 - def tostringRecursions = _tostringRecursions - def tostringRecursions_=(value: Int) = _tostringRecursions = value + private var _toStringSubjects = HashSet[Type]() + def toStringSubjects = _toStringSubjects protected def typeToString(tpe: Type): String = - if (tostringRecursions >= maxTostringRecursions) { + // if (toStringSubjects contains tpe) { + // // handles self-referential anonymous classes and who knows what else + // "..." + // } + // else + if (toStringRecursions >= maxToStringRecursions) { devWarning("Exceeded recursion depth attempting to print " + util.shortClassOfInstance(tpe)) if (settings.debug) (new Throwable).printStackTrace @@ -24,9 +34,15 @@ private[internal] trait TypeToStrings { } else try { - tostringRecursions += 1 + toStringRecursions += 1 + // TODO: study performance impact of this cache + // to quote Jason: + // I'm a little uneasy with the performance impact of the fail-safe. We end up calling Type#toString + // when we generate error messages, including, importantly, errors issued during silent mode that are never issued. + // toStringSubjects += tpe tpe.safeToString } finally { - tostringRecursions -= 1 + // toStringSubjects -= tpe + toStringRecursions -= 1 } } diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index addc7eb389..786ff2210c 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -144,7 +144,7 @@ trait Erasure { else apply(mt.resultType(mt.paramTypes))) case RefinedType(parents, decls) => apply(mergeParents(parents)) - case AnnotatedType(_, atp, _) => + case AnnotatedType(_, atp) => apply(atp) case ClassInfoType(parents, decls, clazz) => ClassInfoType( diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala index 15cfda26b5..f3eedb88e7 100644 --- a/src/reflect/scala/reflect/internal/util/Position.scala +++ b/src/reflect/scala/reflect/internal/util/Position.scala @@ -202,12 +202,31 @@ private[util] trait InternalPositionImpl { def line: Int = if (hasSource) source.offsetToLine(point) + 1 else 0 def column: Int = if (hasSource) calculateColumn() else 0 def lineContent: String = if (hasSource) source.lineToString(line - 1) else "" - def lineCarat: String = if (hasSource) " " * (column - 1) + "^" else "" - - def showError(msg: String): String = finalPosition match { - case FakePos(fmsg) => s"$fmsg $msg" - case NoPosition => msg - case pos => s"${pos.line}: $msg\n${pos.lineContent}\n${pos.lineCarat}" + def lineCaret: String = if (hasSource) " " * (column - 1) + "^" else "" + @deprecated("use `lineCaret`", since="2.11.0") + def lineCarat: String = lineCaret + + def showError(msg: String): String = { + def escaped(s: String) = { + def u(c: Int) = f"\\u$c%04x" + def uable(c: Int) = (c < 0x20 && c != '\t') || c == 0x7F + if (s exists (c => uable(c))) { + val sb = new StringBuilder + s foreach (c => sb append (if (uable(c)) u(c) else c)) + sb.toString + } else s + } + def errorAt(p: Pos) = { + def where = p.line + def content = escaped(p.lineContent) + def indicator = p.lineCaret + f"$where: $msg%n$content%n$indicator" + } + finalPosition match { + case FakePos(fmsg) => s"$fmsg $msg" + case NoPosition => msg + case pos => errorAt(pos) + } } def showDebug: String = toString def show = ( @@ -239,8 +258,8 @@ private[util] trait InternalPositionImpl { private[util] trait DeprecatedPosition { self: Position => - @deprecated("use `point`", "2.9.0") - def offset: Option[Int] = if (isDefined) Some(point) else None // used by sbt + @deprecated("use `point`", "2.9.0") // Used in SBT 0.12.4 + def offset: Option[Int] = if (isDefined) Some(point) else None @deprecated("use `focus`", "2.11.0") def toSingleLine: Position = this @@ -254,7 +273,7 @@ private[util] trait DeprecatedPosition { @deprecated("use `finalPosition`", "2.11.0") def inUltimateSource(source: SourceFile): Position = source positionInUltimateSource this - @deprecated("use `lineCarat`", "2.11.0") + @deprecated("use `lineCaret`", since="2.11.0") def lineWithCarat(maxWidth: Int): (String, String) = ("", "") @deprecated("Use `withSource(source)` and `withShift`", "2.11.0") diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala index 3b6c57e955..9866b043bb 100644 --- a/src/reflect/scala/reflect/internal/util/SourceFile.scala +++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala @@ -16,12 +16,13 @@ import scala.reflect.internal.Chars._ /** abstract base class of a source file used in the compiler */ abstract class SourceFile { - def content : Array[Char] // normalized, must end in SU - def file : AbstractFile - def isLineBreak(idx : Int) : Boolean + def content: Array[Char] // normalized, must end in SU + def file : AbstractFile + def isLineBreak(idx: Int): Boolean + def isEndOfLine(idx: Int): Boolean def isSelfContained: Boolean def length : Int - def position(offset: Int) : Position = { + def position(offset: Int): Position = { assert(offset < length, file + ": " + offset + " >= " + length) Position.offset(this, offset) } @@ -36,8 +37,12 @@ abstract class SourceFile { override def toString() = file.name def path = file.path - def lineToString(index: Int): String = - content drop lineToOffset(index) takeWhile (c => !isLineBreakChar(c.toChar)) mkString "" + def lineToString(index: Int): String = { + val start = lineToOffset(index) + var end = start + while (!isEndOfLine(end)) end += 1 + content.slice(start, end) mkString "" + } @tailrec final def skipWhitespace(offset: Int): Int = @@ -52,6 +57,7 @@ object NoSourceFile extends SourceFile { def content = Array() def file = NoFile def isLineBreak(idx: Int) = false + def isEndOfLine(idx: Int) = false def isSelfContained = true def length = -1 def offsetToLine(offset: Int) = -1 @@ -128,18 +134,24 @@ class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extend super.identifier(pos) } - def isLineBreak(idx: Int) = - if (idx >= length) false else { - val ch = content(idx) - // don't identify the CR in CR LF as a line break, since LF will do. - if (ch == CR) (idx + 1 == length) || (content(idx + 1) != LF) - else isLineBreakChar(ch) - } + private def charAtIsEOL(idx: Int)(p: Char => Boolean) = { + // don't identify the CR in CR LF as a line break, since LF will do. + def notCRLF0 = content(idx) != CR || idx + 1 >= length || content(idx + 1) != LF + + idx < length && notCRLF0 && p(content(idx)) + } + + def isLineBreak(idx: Int) = charAtIsEOL(idx)(isLineBreakChar) + + def isEndOfLine(idx: Int) = charAtIsEOL(idx) { + case CR | LF => true + case _ => false + } def calculateLineIndices(cs: Array[Char]) = { val buf = new ArrayBuffer[Int] buf += 0 - for (i <- 0 until cs.length) if (isLineBreak(i)) buf += i + 1 + for (i <- 0 until cs.length) if (isEndOfLine(i)) buf += i + 1 buf += cs.length // sentinel, so that findLine below works smoother buf.toArray } @@ -149,8 +161,8 @@ class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extend private var lastLine = 0 - /** Convert offset to line in this source file - * Lines are numbered from 0 + /** Convert offset to line in this source file. + * Lines are numbered from 0. */ def offsetToLine(offset: Int): Int = { val lines = lineIndices diff --git a/src/reflect/scala/reflect/macros/Aliases.scala b/src/reflect/scala/reflect/macros/Aliases.scala index ca599dbd49..d2b878d081 100644 --- a/src/reflect/scala/reflect/macros/Aliases.scala +++ b/src/reflect/scala/reflect/macros/Aliases.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that defines shorthands for the + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that defines shorthands for the * most frequently used types and functions of the underlying compiler universe. */ trait Aliases { - self: BlackboxContext => + self: blackbox.Context => /** The type of symbols representing declarations. */ type Symbol = universe.Symbol @@ -40,10 +40,16 @@ trait Aliases { /** The type of tree modifiers. */ type Modifiers = universe.Modifiers - /** The type of compilation runs. */ + /** The type of compilation runs. + * @see [[scala.reflect.macros.Enclosures]] + */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") type Run = universe.Run - /** The type of compilation units. */ + /** The type of compilation units. + * @see [[scala.reflect.macros.Enclosures]] + */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") type CompilationUnit = universe.CompilationUnit /** Expr wraps an abstract syntax tree and tags it with its type. */ diff --git a/src/reflect/scala/reflect/macros/BlackboxMacro.scala b/src/reflect/scala/reflect/macros/BlackboxMacro.scala deleted file mode 100644 index df142e9238..0000000000 --- a/src/reflect/scala/reflect/macros/BlackboxMacro.scala +++ /dev/null @@ -1,36 +0,0 @@ -package scala.reflect -package macros - -/** - * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> - * - * Traditionally macro implementations are defined as methods, - * but this trait provides an alternative way of encoding macro impls as - * bundles, traits which extend `scala.reflect.macros.BlackboxMacro` or`scala.reflect.macros.WhiteboxMacro` . - * - * Instead of: - * - * def impl[T: c.WeakTypeTag](c: BlackboxContext)(x: c.Expr[Int]) = ... - * - * One can write: - * - * trait Impl extends BlackboxMacro { - * def apply[T: c.WeakTypeTag](x: c.Expr[Int]) = ... - * } - * - * Without changing anything else at all. - * - * This language feature is useful in itself in cases when macro implementations - * are complex and need to be modularized. State of the art technique of addressing this need is quite heavyweight: - * http://docs.scala-lang.org/overviews/macros/overview.html#writing_bigger_macros. - * - * @see `scala.reflect.macros.WhiteboxMacro` - */ -trait BlackboxMacro { - /** The context to be used by the macro implementation. - * - * Vanilla macro implementations have to carry it in their signatures, however when a macro is a full-fledged module, - * it can define the context next to the implementation, makes implementation signature more lightweight. - */ - val c: BlackboxContext -} diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala index f3e934d12b..1ced2e54c6 100644 --- a/src/reflect/scala/reflect/macros/Enclosures.scala +++ b/src/reflect/scala/reflect/macros/Enclosures.scala @@ -7,13 +7,25 @@ import scala.language.existentials // SI-6541 /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that exposes - * enclosing trees (method, class, compilation unit and currently compiled application), + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that exposes + * enclosing trees (method, class, compilation unit and currently compiled macro application), * the enclosing position of the macro expansion, as well as macros and implicits * that are currently in-flight. + * + * Starting from Scala 2.11.0, the APIs to get the trees enclosing by the current macro application are deprecated, + * and the reasons for that are two-fold. Firstly, we would like to move towards the philosophy of locally-expanded macros, + * as it has proven to be important for understanding of code. Secondly, within the current architecture of scalac, + * we are unable to have c.enclosingTree-style APIs working robustly. Required changes to the typechecker would greatly + * exceed the effort that we would like to expend on this feature given the existence of more pressing concerns at the moment. + * This is somewhat aligned with the overall evolution of macros during the 2.11 development cycle, where we played with + * `c.introduceTopLevel` and `c.introduceMember`, but at the end of the day decided to reject them. + * + * If you're relying on the now deprecated APIs, consider reformulating your macros in terms of completely local expansion + * and/or joining a discussion of a somewhat related potential language feature at [[https://groups.google.com/forum/#!topic/scala-debate/f4CLmYShX6Q]]. + * We also welcome questions and suggestions on our mailing lists, where we would be happy to further discuss this matter. */ trait Enclosures { - self: BlackboxContext => + self: blackbox.Context => /** The tree that undergoes macro expansion. * Can be useful to get an offset or a range position of the entire tree being processed. @@ -30,7 +42,7 @@ trait Enclosures { * Unlike `openMacros`, this is a val, which means that it gets initialized when the context is created * and always stays the same regardless of whatever happens during macro expansion. */ - def enclosingMacros: List[BlackboxContext] + def enclosingMacros: List[blackbox.Context] /** Tries to guess a position for the enclosing application. * But that is simple, right? Just dereference `pos` of `macroApplication`? Not really. @@ -40,46 +52,62 @@ trait Enclosures { def enclosingPosition: Position /** Tree that corresponds to the enclosing method, or EmptyTree if not applicable. + * @see [[scala.reflect.macros.Enclosures]] */ - @deprecated("Use enclosingDef instead, but be wary of changes in semantics", "2.10.1") + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingMethod: Tree /** Tree that corresponds to the enclosing class, or EmptyTree if not applicable. + * @see [[scala.reflect.macros.Enclosures]] */ - @deprecated("Use enclosingImpl instead, but be wary of changes in semantics", "2.10.1") + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingClass: Tree /** Tree that corresponds to the enclosing DefDef tree. * Throws `EnclosureException` if there's no such enclosing tree. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingDef: universe.DefDef /** Tree that corresponds to the enclosing Template tree. * Throws `EnclosureException` if there's no such enclosing tree. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingTemplate: universe.Template /** Tree that corresponds to the enclosing ImplDef tree (i.e. either ClassDef or ModuleDef). * Throws `EnclosureException` if there's no such enclosing tree. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingImpl: universe.ImplDef /** Tree that corresponds to the enclosing PackageDef tree. * Throws `EnclosureException` if there's no such enclosing tree. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingPackage: universe.PackageDef /** Compilation unit that contains this macro application. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingUnit: CompilationUnit /** Compilation run that contains this macro application. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingRun: Run /** Indicates than one of the enclosure methods failed to find a tree * of required type among enclosing trees. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") case class EnclosureException(expected: Class[_], enclosingTrees: List[Tree]) extends Exception(s"Couldn't find a tree of type $expected among enclosing trees $enclosingTrees") } diff --git a/src/reflect/scala/reflect/macros/Evals.scala b/src/reflect/scala/reflect/macros/Evals.scala index eb37e83cad..222ae43d79 100644 --- a/src/reflect/scala/reflect/macros/Evals.scala +++ b/src/reflect/scala/reflect/macros/Evals.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that provides + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that provides * a facility to evaluate trees. */ trait Evals { - self: BlackboxContext => + self: blackbox.Context => /** Takes a typed wrapper for a tree of type `T` and evaluates it to a value of type `T`. * @@ -21,12 +21,12 @@ trait Evals { * mutates the tree in place, therefore the conventional approach is to `duplicate` the tree first. * * {{{ - * scala> def impl(c: BlackboxContext)(x: c.Expr[String]) = { + * scala> def impl(c: Context)(x: c.Expr[String]) = { * | val x1 = c.Expr[String](c.resetAllAttrs(x.tree.duplicate)) * | println(s"compile-time value is: \${c.eval(x1)}") * | x * | } - * impl: (c: BlackboxContext)(x: c.Expr[String])c.Expr[String] + * impl: (c: Context)(x: c.Expr[String])c.Expr[String] * * scala> def test(x: String) = macro impl * test: (x: String)String diff --git a/src/reflect/scala/reflect/macros/ExprUtils.scala b/src/reflect/scala/reflect/macros/ExprUtils.scala index 58b61e446a..c438653c92 100644 --- a/src/reflect/scala/reflect/macros/ExprUtils.scala +++ b/src/reflect/scala/reflect/macros/ExprUtils.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that defines shorthands for the + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that defines shorthands for the * most common `Expr`-creating functions. */ trait ExprUtils { - self: BlackboxContext => + self: blackbox.Context => /** Shorthand for `Literal(Constant(null))` in the underlying `universe`. */ @deprecated("Use quasiquotes instead", "2.11.0") diff --git a/src/reflect/scala/reflect/macros/FrontEnds.scala b/src/reflect/scala/reflect/macros/FrontEnds.scala index 3a910d89ad..a770f325b2 100644 --- a/src/reflect/scala/reflect/macros/FrontEnds.scala +++ b/src/reflect/scala/reflect/macros/FrontEnds.scala @@ -5,12 +5,12 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * provides facilities to communicate with the compiler's front end * (emit warnings, errors and other sorts of messages). */ trait FrontEnds { - self: BlackboxContext => + self: blackbox.Context => /** For sending a message which should not be labeled as a warning/error, * but also shouldn't require -verbose to be visible. diff --git a/src/reflect/scala/reflect/macros/Infrastructure.scala b/src/reflect/scala/reflect/macros/Infrastructure.scala index b6585f94d2..0f2d9ce4cf 100644 --- a/src/reflect/scala/reflect/macros/Infrastructure.scala +++ b/src/reflect/scala/reflect/macros/Infrastructure.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * provides facilities to communicate with the compiler's infrastructure. */ trait Infrastructure { - self: BlackboxContext => + self: blackbox.Context => /** Exposes macro-specific settings as a list of strings. * These settings are passed to the compiler via the "-Xmacro-settings:setting1,setting2...,settingN" command-line option. diff --git a/src/reflect/scala/reflect/macros/Names.scala b/src/reflect/scala/reflect/macros/Names.scala index 6bd3e1a199..af60dffbfc 100644 --- a/src/reflect/scala/reflect/macros/Names.scala +++ b/src/reflect/scala/reflect/macros/Names.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * provides functions that generate unique names. */ trait Names { - self: BlackboxContext => + self: blackbox.Context => /** Creates a unique string. */ @deprecated("Use freshName instead", "2.11.0") diff --git a/src/reflect/scala/reflect/macros/Parsers.scala b/src/reflect/scala/reflect/macros/Parsers.scala index 9d4a7e2953..720b754649 100644 --- a/src/reflect/scala/reflect/macros/Parsers.scala +++ b/src/reflect/scala/reflect/macros/Parsers.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * exposes functions to parse strings with Scala code into trees. */ trait Parsers { - self: BlackboxContext => + self: blackbox.Context => /** Parses a string with a Scala expression into an abstract syntax tree. * Only works for expressions, i.e. parsing a package declaration will fail. diff --git a/src/reflect/scala/reflect/macros/Reifiers.scala b/src/reflect/scala/reflect/macros/Reifiers.scala index 67d10dc10a..ff1f7a3b28 100644 --- a/src/reflect/scala/reflect/macros/Reifiers.scala +++ b/src/reflect/scala/reflect/macros/Reifiers.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * exposes functions to save reflection artifacts for runtime. */ trait Reifiers { - self: BlackboxContext => + self: blackbox.Context => /** Given a tree, generate a tree that when compiled and executed produces the original tree. * For more information and examples see the documentation for `Universe.reify`. diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala index f215e8769d..87de442921 100644 --- a/src/reflect/scala/reflect/macros/Typers.scala +++ b/src/reflect/scala/reflect/macros/Typers.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * partially exposes the type checker to macro writers. */ trait Typers { - self: BlackboxContext => + self: blackbox.Context => /** Contexts that represent macros in-flight, including the current one. Very much like a stack trace, but for macros only. * Can be useful for interoperating with other macros and for imposing compiler-friendly limits on macro expansion. @@ -21,7 +21,7 @@ trait Typers { * Unlike `enclosingMacros`, this is a def, which means that it gets recalculated on every invocation, * so it might change depending on what is going on during macro expansion. */ - def openMacros: List[BlackboxContext] + def openMacros: List[blackbox.Context] /** @see `Typers.typecheck` */ diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index 297bac2999..d84e6aa737 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -197,34 +197,44 @@ abstract class Universe extends scala.reflect.api.Universe { def capturedVariableType(vble: Symbol): Type /** The type of compilation runs. + * @see [[scala.reflect.macros.Enclosures]] * @template * @group Macros */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") type Run <: RunContextApi /** Compilation run uniquely identifies current invocation of the compiler * (e.g. can be used to implement per-run caches for macros) and provides access to units of work * of the invocation (currently processed unit of work and the list of all units). + * @see [[scala.reflect.macros.Enclosures]] * @group API */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") trait RunContextApi { /** Currently processed unit of work (a real or a virtual file). */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def currentUnit: CompilationUnit /** All units of work comprising this compilation run. */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def units: Iterator[CompilationUnit] } /** The type of compilation units. + * @see [[scala.reflect.macros.Enclosures]] * @template * @group Macros */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") type CompilationUnit <: CompilationUnitContextApi /** Compilation unit describes a unit of work of the compilation run. * It provides such information as file name, textual representation of the unit and the underlying AST. + * @see [[scala.reflect.macros.Enclosures]] * @group API */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") trait CompilationUnitContextApi { /** Source file corresponding to this compilation unit. * @@ -235,9 +245,11 @@ abstract class Universe extends scala.reflect.api.Universe { * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined * and exposed as a part of scala.reflect.api. */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def source: scala.reflect.internal.util.SourceFile /** The AST that corresponds to this compilation unit. */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def body: Tree } } diff --git a/src/reflect/scala/reflect/macros/WhiteboxMacro.scala b/src/reflect/scala/reflect/macros/WhiteboxMacro.scala deleted file mode 100644 index 1c581313eb..0000000000 --- a/src/reflect/scala/reflect/macros/WhiteboxMacro.scala +++ /dev/null @@ -1,36 +0,0 @@ -package scala.reflect -package macros - -/** - * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> - * - * Traditionally macro implementations are defined as methods, - * but this trait provides an alternative way of encoding macro impls as - * bundles, traits which extend `scala.reflect.macros.BlackboxMacro` or`scala.reflect.macros.WhiteboxMacro` . - * - * Instead of: - * - * def impl[T: c.WeakTypeTag](c: WhiteboxContext)(x: c.Expr[Int]) = ... - * - * One can write: - * - * trait Impl extends WhiteboxMacro { - * def apply[T: c.WeakTypeTag](x: c.Expr[Int]) = ... - * } - * - * Without changing anything else at all. - * - * This language feature is useful in itself in cases when macro implementations - * are complex and need to be modularized. State of the art technique of addressing this need is quite heavyweight: - * http://docs.scala-lang.org/overviews/macros/overview.html#writing_bigger_macros. - * - * @see `scala.reflect.macros.BlackboxMacro` - */ -trait WhiteboxMacro { - /** The context to be used by the macro implementation. - * - * Vanilla macro implementations have to carry it in their signatures, however when a macro is a full-fledged module, - * it can define the context next to the implementation, makes implementation signature more lightweight. - */ - val c: WhiteboxContext -} diff --git a/src/reflect/scala/reflect/macros/BlackboxContext.scala b/src/reflect/scala/reflect/macros/blackbox/Context.scala index 2c77289866..05d9595c3a 100644 --- a/src/reflect/scala/reflect/macros/BlackboxContext.scala +++ b/src/reflect/scala/reflect/macros/blackbox/Context.scala @@ -1,6 +1,7 @@ package scala package reflect package macros +package blackbox /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> @@ -24,24 +25,24 @@ package macros * enclosing trees and compilation units, evaluating trees, logging warnings/errors and much more. * Refer to the documentation of top-level traits in this package to learn the details. * - * If a macro def refers to a macro impl that uses `BlackboxContext`, then this macro def becomes a blackbox macro, + * If a macro def refers to a macro impl that uses `blackbox.Context`, then this macro def becomes a blackbox macro, * which means that its expansion will be upcast to its return type, enforcing faithfullness of that macro to its - * type signature. Whitebox macros, i.e. the ones defined with `WhiteboxContext`, aren't bound by this restriction, + * type signature. Whitebox macros, i.e. the ones defined with `whitebox.Context`, aren't bound by this restriction, * which enables a number of important use cases, but they are also going to enjoy less support than blackbox macros, * so choose wisely. See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] for more information. * - * @see `scala.reflect.macros.WhiteboxContext` + * @see `scala.reflect.macros.whitebox.Context` */ -trait BlackboxContext extends Aliases - with Enclosures - with Names - with Reifiers - with FrontEnds - with Infrastructure - with Typers - with Parsers - with Evals - with ExprUtils { +trait Context extends Aliases + with Enclosures + with Names + with Reifiers + with FrontEnds + with Infrastructure + with Typers + with Parsers + with Evals + with ExprUtils { /** The compile-time universe. */ val universe: Universe @@ -63,7 +64,7 @@ trait BlackboxContext extends Aliases * scala> class Coll[T] { * | def filter(p: T => Boolean): Coll[T] = macro M.filter[T] * | }; object M { - * | def filter[T](c: BlackboxContext { type PrefixType = Coll[T] }) + * | def filter[T](c: Context { type PrefixType = Coll[T] }) * | (p: c.Expr[T => Boolean]): c.Expr[Coll[T]] = * | { * | println(c.prefix.tree) diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala index 6a8434a163..cc7111d794 100644 --- a/src/reflect/scala/reflect/macros/package.scala +++ b/src/reflect/scala/reflect/macros/package.scala @@ -19,10 +19,10 @@ package object macros { * with the former being better supported and the latter being more powerful. You can read about * the details of the split and the associated trade-offs in the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]]. * - * `scala.reflect.macros.Context` follows this tendency and turns into `scala.reflect.macros.BlackboxContext` - * and `scala.reflect.macros.WhiteboxContext`. The original `Context` is left in place for compatibility reasons, + * `scala.reflect.macros.Context` follows this tendency and turns into `scala.reflect.macros.blackbox.Context` + * and `scala.reflect.macros.whitebox.Context`. The original `Context` is left in place for compatibility reasons, * but it is now deprecated, nudging the users to choose between blackbox and whitebox macros. */ - @deprecated("Use BlackboxContext or WhiteboxContext instead", "2.11.0") - type Context = WhiteboxContext + @deprecated("Use blackbox.Context or whitebox.Context instead", "2.11.0") + type Context = whitebox.Context }
\ No newline at end of file diff --git a/src/reflect/scala/reflect/macros/WhiteboxContext.scala b/src/reflect/scala/reflect/macros/whitebox/Context.scala index 9d65a5c16e..bd48df46cc 100644 --- a/src/reflect/scala/reflect/macros/WhiteboxContext.scala +++ b/src/reflect/scala/reflect/macros/whitebox/Context.scala @@ -1,6 +1,7 @@ package scala package reflect package macros +package whitebox /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> @@ -24,22 +25,22 @@ package macros * enclosing trees and compilation units, evaluating trees, logging warnings/errors and much more. * Refer to the documentation of top-level traits in this package to learn the details. * - * If a macro def refers to a macro impl that uses `WhiteboxContext`, then this macro def becomes a whitebox macro, + * If a macro def refers to a macro impl that uses `whitebox.Context`, then this macro def becomes a whitebox macro, * gaining the ability to refine the type of its expansion beyond its official return type, which enables a number of important use cases. - * Blackbox macros, i.e. the ones defined with `BlackboxContext`, can't do that, so they are less powerful. + * Blackbox macros, i.e. the ones defined with `blackbox.Context`, can't do that, so they are less powerful. * However blackbox macros are also going to enjoy better support than whitebox macros, so choose wisely. * See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] for more information. * - * @see `scala.reflect.macros.BlackboxContext` + * @see `scala.reflect.macros.blackbox.Context` */ -trait WhiteboxContext extends BlackboxContext { +trait Context extends blackbox.Context { /** @inheritdoc */ - def openMacros: List[WhiteboxContext] + def openMacros: List[Context] /** @inheritdoc */ - def enclosingMacros: List[WhiteboxContext] + def enclosingMacros: List[Context] /** Information about one of the currently considered implicit candidates. * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters, diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 9dfa5bcf2e..b9b171c7ed 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -41,7 +41,8 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => // inaccessible: this._lubResults // inaccessible: this._glbResults // inaccessible: this._indent - // inaccessible: this._tostringRecursions + // inaccessible: this._toStringRecursions + // inaccessible: this._toStringSubjects // inaccessible: this.atomicIds // inaccessible: this.atomicExistentialIds // inaccessible: this._recursionTable @@ -199,6 +200,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.ErroneousCollector this.adaptToNewRunMap // inaccessible: this.commonOwnerMapObj + this.SubTypePair this.SymbolKind this.NoSymbol this.CyclicReference @@ -274,6 +276,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.ComparableClass definitions.JavaCloneableClass definitions.JavaNumberClass + definitions.JavaEnumClass definitions.RemoteInterfaceClass definitions.RemoteExceptionClass definitions.ByNameParamClass @@ -320,8 +323,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.MirrorClass definitions.TypeCreatorClass definitions.TreeCreatorClass - definitions.BlackboxMacroClass - definitions.WhiteboxMacroClass definitions.BlackboxContextClass definitions.WhiteboxContextClass definitions.MacroImplAnnotation diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala index de78e527a7..83d471f91e 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala @@ -81,9 +81,12 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa override def indent = _indent.get override def indent_=(value: String) = _indent.set(value) - private lazy val _tostringRecursions = mkThreadLocalStorage(0) - override def tostringRecursions = _tostringRecursions.get - override def tostringRecursions_=(value: Int) = _tostringRecursions.set(value) + private lazy val _toStringRecursions = mkThreadLocalStorage(0) + override def toStringRecursions = _toStringRecursions.get + override def toStringRecursions_=(value: Int) = _toStringRecursions.set(value) + + private lazy val _toStringSubjects = mkThreadLocalStorage(new mutable.HashSet[Type]) + override def toStringSubjects = _toStringSubjects.get /* The idea of caches is as follows. * When in reflexive mode, a cache is either null, or one sentinal diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala index 3a7688aa2c..3c9bbccba3 100644 --- a/src/reflect/scala/reflect/runtime/package.scala +++ b/src/reflect/scala/reflect/runtime/package.scala @@ -26,7 +26,7 @@ package object runtime { package runtime { private[scala] object Macros { - def currentMirror(c: scala.reflect.macros.BlackboxContext): c.Expr[universe.Mirror] = { + def currentMirror(c: scala.reflect.macros.blackbox.Context): c.Expr[universe.Mirror] = { import c.universe._ val runtimeClass = c.reifyEnclosingRuntimeClass if (runtimeClass.isEmpty) c.abort(c.enclosingPosition, "call site does not have an enclosing class") |