diff options
Diffstat (limited to 'src/reflect')
7 files changed, 57 insertions, 8 deletions
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 260974a981..3a69390bcf 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -72,6 +72,8 @@ private[reflect] trait BuildUtils { self: Universe => def setSymbol[T <: Tree](tree: T, sym: Symbol): T + def toStats(tree: Tree): List[Tree] + def mkAnnotation(tree: Tree): Tree def mkAnnotation(trees: List[Tree]): List[Tree] diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 3061885549..16bb3e5989 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -61,6 +61,8 @@ trait BuildUtils { self: SymbolTable => def setSymbol[T <: Tree](tree: T, sym: Symbol): T = { tree.setSymbol(sym); tree } + def toStats(tree: Tree): List[Tree] = SyntacticBlock.unapply(tree).get + def mkAnnotation(tree: Tree): Tree = tree match { case SyntacticNew(Nil, SyntacticApplied(SyntacticTypeApplied(_, _), _) :: Nil, noSelfType, Nil) => tree @@ -381,13 +383,41 @@ trait BuildUtils { self: SymbolTable => } } + object SyntheticUnit { + def unapply(tree: Tree): Boolean = tree match { + case Literal(Constant(())) if tree.hasAttachment[SyntheticUnitAttachment.type] => true + case _ => false + } + } + + /** Syntactic combinator that abstracts over Block tree. + * + * Apart from providing a more straightforward api that exposes + * block as a list of elements rather than (stats, expr) pair + * it also: + * + * 1. Treats of q"" (empty tree) as zero-element block. + * + * 2. Strips trailing synthetic units which are inserted by the + * compiler if the block ends with a definition rather + * than an expression. + * + * 3. Matches non-block term trees and recognizes them as + * single-element blocks for sake of consistency with + * compiler's default to treat single-element blocks with + * expressions as just expressions. + */ object SyntacticBlock extends SyntacticBlockExtractor { - def apply(stats: List[Tree]): Tree = gen.mkBlock(stats) + def apply(stats: List[Tree]): Tree = + if (stats.isEmpty) EmptyTree + else gen.mkBlock(stats) def unapply(tree: Tree): Option[List[Tree]] = tree match { - case self.Block(stats, expr) => Some(stats :+ expr) - case _ if tree.isTerm => Some(tree :: Nil) - case _ => None + case self.Block(stats, SyntheticUnit()) => Some(stats) + case self.Block(stats, expr) => Some(stats :+ expr) + case EmptyTree => Some(Nil) + case _ if tree.isTerm => Some(tree :: Nil) + case _ => None } } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 5b06239863..4d24f0b219 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -625,6 +625,7 @@ trait Definitions extends api.StandardDefinitions { def isBlackboxMacroBundleType(tp: Type) = isMacroBundleType(tp) && (macroBundleParamInfo(tp) <:< BlackboxContextClass.tpe) + def isListType(tp: Type) = tp <:< classExistentialType(ListClass) def isIterableType(tp: Type) = tp <:< classExistentialType(IterableClass) // These "direct" calls perform no dealiasing. They are most needed when diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 09fd996f39..139a79ffe1 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -36,6 +36,10 @@ trait StdAttachments { */ case object ForAttachment extends PlainAttachment + /** Identifies unit constants which were inserted by the compiler (e.g. gen.mkBlock) + */ + case object SyntheticUnitAttachment extends PlainAttachment + /** Untyped list of subpatterns attached to selector dummy. */ case class SubpatternsAttachment(patterns: List[Tree]) } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 7015105261..256d5759fa 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -752,6 +752,7 @@ trait StdNames { val toArray: NameType = "toArray" val toList: NameType = "toList" val toObjectArray : NameType = "toObjectArray" + val toStats: NameType = "toStats" val TopScope: NameType = "TopScope" val toString_ : NameType = "toString" val toTypeConstructor: NameType = "toTypeConstructor" diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index b16cbd8325..e602a12175 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -342,7 +342,7 @@ abstract class TreeGen extends macros.TreeBuilder { } param } - + val (edefs, rest) = body span treeInfo.isEarlyDef val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef val gvdefs = evdefs map { @@ -381,11 +381,11 @@ abstract class TreeGen extends macros.TreeBuilder { } constr foreach (ensureNonOverlapping(_, parents ::: gvdefs, focus = false)) // Field definitions for the class - remove defaults. - + val fieldDefs = vparamss.flatten map (vd => { val field = copyValDef(vd)(mods = vd.mods &~ DEFAULTPARAM, rhs = EmptyTree) // Prevent overlapping of `field` end's position with default argument's start position. - // This is needed for `Positions.Locator(pos).traverse` to return the correct tree when + // This is needed for `Positions.Locator(pos).traverse` to return the correct tree when // the `pos` is a point position with all its values equal to `vd.rhs.pos.start`. if(field.pos.isRange && vd.rhs.pos.isRange) field.pos = field.pos.withEnd(vd.rhs.pos.start - 1) field @@ -444,13 +444,23 @@ abstract class TreeGen extends macros.TreeBuilder { def mkFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe)) + /** Create a literal unit tree that is inserted by the compiler but not + * written by end user. It's important to distinguish the two so that + * quasiquotes can strip synthetic ones away. + */ + def mkSyntheticUnit() = Literal(Constant(())).updateAttachment(SyntheticUnitAttachment) + /** Create block of statements `stats` */ def mkBlock(stats: List[Tree]): Tree = if (stats.isEmpty) Literal(Constant(())) - else if (!stats.last.isTerm) Block(stats, Literal(Constant(()))) + else if (!stats.last.isTerm) Block(stats, mkSyntheticUnit()) else if (stats.length == 1) stats.head else Block(stats.init, stats.last) + /** Create a block that wraps multiple statements but don't + * do any wrapping if there is just one statement. Used by + * quasiquotes, macro c.parse api and toolbox. + */ def mkTreeOrBlock(stats: List[Tree]) = stats match { case Nil => EmptyTree case head :: Nil => head diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index b9b171c7ed..8811b5513e 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -58,6 +58,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.CompoundTypeTreeOriginalAttachment this.BackquotedIdentifierAttachment this.ForAttachment + this.SyntheticUnitAttachment this.SubpatternsAttachment this.noPrint this.typeDebug |