diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-02-21 15:02:43 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-02-21 15:02:43 +0100 |
commit | 25f23a443bc6831d1c8d7f6f57212a29e84bbaa5 (patch) | |
tree | e281e0034c7c3de89b1969da1791ab91daf66b54 | |
parent | d79fc2cae4e550bf0a3276a3961ed007bdd428e7 (diff) | |
parent | 48a706dee8f7df9d1a6267b6b117cf1546915506 (diff) | |
download | scala-25f23a443bc6831d1c8d7f6f57212a29e84bbaa5.tar.gz scala-25f23a443bc6831d1c8d7f6f57212a29e84bbaa5.tar.bz2 scala-25f23a443bc6831d1c8d7f6f57212a29e84bbaa5.zip |
Merge pull request #3546 from VladimirNik/typedTreesPrinter-2.11.0
CodePrinter added to Printers 2.11.0
-rw-r--r-- | src/reflect/scala/reflect/api/Printers.scala | 12 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Printers.scala | 184 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/ReificationSupport.scala | 8 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/TreeInfo.scala | 61 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Trees.scala | 10 | ||||
-rw-r--r-- | test/files/run/t7185.check | 4 | ||||
-rw-r--r-- | test/files/scalacheck/quasiquotes/TypecheckedProps.scala | 72 | ||||
-rw-r--r-- | test/junit/scala/reflect/internal/PrintersTest.scala | 2 |
8 files changed, 292 insertions, 61 deletions
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala index b262fdce68..92ae6d8b44 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -209,20 +209,22 @@ trait Printers { self: Universe => * 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. + * #1 is available for unattributed trees and attributed trees * #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. + * left in place, and that's what we plan to improve in the future. + * printTypes, printIds, printPositions options have the same meaning as for TreePrinter + * printRootPkg option is available only for attributed trees. * * @group Printers */ - def showCode(tree: Tree) = render(tree, newCodePrinter) + def showCode(tree: Tree, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printPositions: BooleanFlag = None, printRootPkg: Boolean = false) = + render(tree, newCodePrinter(_, tree, printRootPkg), printTypes, printIds, printOwners, printKinds = None, printMirrors = None, printPositions) /** * Hook to define what `showCode(...)` means. * @group Printers */ - protected def newCodePrinter(out: PrintWriter): TreePrinter + protected def newCodePrinter(out: PrintWriter, tree: Tree, printRootPkg: Boolean): TreePrinter /** Renders internal structure of a reflection artifact as the * visualization of a Scala syntax tree. diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index b1d76b6056..680c19e426 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -73,7 +73,14 @@ trait Printers extends api.Printers { self: SymbolTable => def indent() = indentMargin += indentStep def undent() = indentMargin -= indentStep - def printPosition(tree: Tree) = if (printPositions) print(tree.pos.show) + def printPosition(tree: Tree) = + if (printPositions) comment(print(tree.pos.show)) + + protected def printTypesInfo(tree: Tree) = + if (printTypes && tree.isTerm && tree.canHaveAttrs) + comment{ + print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}") + } def println() = { out.println() @@ -124,12 +131,17 @@ trait Printers extends api.Printers { self: SymbolTable => print(symName(p, p.name)); printOpt(": ", TypeTree() setType p.tpe) } - protected def parenthesize(condition: Boolean = true)(body: => Unit) = { - if (condition) print("(") + protected def parenthesize(condition: Boolean = true, open: String = "(", close: String = ")")(body: => Unit) = { + if (condition) print(open) body - if (condition) print(")") + if (condition) print(close) } + protected val commentsRequired = false + + protected def comment(body: => Unit) = + parenthesize(commentsRequired, "/*", "*/")(body) + protected def printImplicitInParamsList(vds: List[ValDef]) = if (vds.nonEmpty) printFlags(vds.head.mods.flags & IMPLICIT, "") @@ -275,13 +287,20 @@ trait Printers extends api.Printers { self: SymbolTable => print("("); printValueParams print(" => ", body, ")") - if (printIds && tree.symbol != null) print("#" + tree.symbol.id) - if (printOwners && tree.symbol != null) print("@" + tree.symbol.owner.id) + if (printIds && tree.symbol != null) + comment{ + print("#" + tree.symbol.id) + } + + if (printOwners && tree.symbol != null) + comment{ + print("@" + tree.symbol.owner.id) + } } - protected def printSuper(tree: Super, resultName: => String) = { + protected def printSuper(tree: Super, resultName: => String, checkSymbol: Boolean = true) = { val Super(This(qual), mix) = tree - if (qual.nonEmpty || tree.symbol != NoSymbol) print(resultName + ".") + if (qual.nonEmpty || (checkSymbol && tree.symbol != NoSymbol)) print(resultName + ".") print("super") if (mix.nonEmpty) print(s"[$mix]") } @@ -292,6 +311,9 @@ trait Printers extends api.Printers { self: SymbolTable => print("this") } + protected def printBlock(stats: List[Tree], expr: Tree) = + printColumn(stats ::: List(expr), "{", ";", "}") + def printTree(tree: Tree) = { tree match { case EmptyTree => @@ -351,7 +373,7 @@ trait Printers extends api.Printers { self: SymbolTable => currentOwner = currentOwner1 case Block(stats, expr) => - printColumn(stats ::: List(expr), "{", ";", "}") + printBlock(stats, expr) case Match(selector, cases) => val selectorType1 = selectorType @@ -498,9 +520,7 @@ trait Printers extends api.Printers { self: SymbolTable => case tree => xprintTree(this, tree) } - if (printTypes && tree.isTerm && tree.canHaveAttrs) { - print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}") - } + printTypesInfo(tree) } def print(args: Any*): Unit = args foreach { @@ -514,21 +534,8 @@ trait Printers extends api.Printers { self: SymbolTable => } } - // 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 - + // it's the printer for AST-based code generation + class CodePrinter(out: PrintWriter, printRootPkg: Boolean) extends TreePrinter(out) { protected val parentsStack = scala.collection.mutable.Stack[Tree]() protected def currentTree = if (parentsStack.nonEmpty) Some(parentsStack.top) else None @@ -558,6 +565,8 @@ trait Printers extends api.Printers { self: SymbolTable => qualIsIntLit && name.isOperatorName } + override protected val commentsRequired = true + 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 { @@ -582,10 +591,21 @@ trait Printers extends api.Printers { self: SymbolTable => 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) + case _ => render(t, new CodePrinter(_, printRootPkg)) } } + protected def emptyTree(tree: Tree) = tree match { + case EmptyTree | build.SyntacticEmptyTypeTree() => true + case _ => false + } + + protected def originalTypeTrees(trees: List[Tree]) = + trees.filter(!emptyTree(_)) map { + case tt: TypeTree => tt.original + case tree => tree + } + 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]) = { @@ -602,9 +622,24 @@ trait Printers extends api.Printers { self: SymbolTable => 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 + protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) = + originalTypeTrees(trees) filter { + case Select(Ident(sc), name) => !(classesToRemove.contains(name) && sc == nme.scala_) + case _ => true + } + + protected def syntheticToRemove(tree: Tree) = + tree match { + case _: ValDef | _: TypeDef => false // don't remove ValDef and TypeDef + case md: MemberDef if md.mods.isSynthetic => true + case _ => false + } + + override def printOpt(prefix: String, tree: Tree) = + if (!emptyTree(tree)) super.printOpt(prefix, tree) + + override def printColumn(ts: List[Tree], start: String, sep: String, end: String) = { + super.printColumn(ts.filter(!syntheticToRemove(_)), start, sep, end) } def printFlags(mods: Modifiers, primaryCtorParam: Boolean = false): Unit = { @@ -635,6 +670,7 @@ trait Printers extends api.Printers { self: SymbolTable => def printParam(tree: Tree, primaryCtorParam: Boolean): Unit = tree match { case vd @ ValDef(mods, name, tp, rhs) => + printPosition(tree) printAnnotations(vd) val mutableOrOverride = mods.isOverride || mods.isMutable val hideCtorMods = mods.isParamAccessor && mods.isPrivateLocal && !mutableOrOverride @@ -648,6 +684,7 @@ trait Printers extends api.Printers { self: SymbolTable => printOpt(": ", tp); printOpt(" = ", rhs) case TypeDef(_, name, tparams, rhs) => + printPosition(tree) print(printedName(name)) printTypeParams(tparams); print(rhs) @@ -682,7 +719,17 @@ trait Printers extends api.Printers { self: SymbolTable => override def printTree(tree: Tree): Unit = { parentsStack.push(tree) + try { + processTreePrinting(tree); + printTypesInfo(tree) + } finally parentsStack.pop() + } + + def processTreePrinting(tree: Tree): Unit = { tree match { + // don't remove synthetic ValDef/TypeDef + case _ if syntheticToRemove(tree) => + case cl @ ClassDef(mods, name, tparams, impl) => if (mods.isJavaDefined) super.printTree(cl) printAnnotations(cl) @@ -733,12 +780,11 @@ trait Printers extends api.Printers { self: SymbolTable => printSeq(stats) { print(_) } { - print(";"); + println() println() }; case _ => - val separator = scala.util.Properties.lineSeparator - printPackageDef(pd, separator) + printPackageDef(pd, scala.util.Properties.lineSeparator) } case md @ ModuleDef(mods, name, impl) => @@ -786,7 +832,8 @@ trait Printers extends api.Printers { self: SymbolTable => case imp @ Import(expr, _) => printImport(imp, resolveSelect(expr)) - case Template(parents, self, body) => + case t @ Template(parents, self, tbody) => + val body = treeInfo.untypecheckedTemplBody(t) val printedParents = currentParent map { case _: CompoundTypeTree => parents @@ -840,7 +887,7 @@ trait Printers extends api.Printers { self: SymbolTable => case dd: DefDef => dd.name != nme.CONSTRUCTOR case _ => true } - val modBody = left ::: right.drop(1) + val modBody = (left ::: right.drop(1)) val showBody = !(modBody.isEmpty && (self == noSelfType || self.isEmpty)) if (showBody) { if (self.name != nme.WILDCARD) { @@ -855,7 +902,8 @@ trait Printers extends api.Printers { self: SymbolTable => printColumn(modBody, "", ";", "}") } - case Block(stats, expr) => super.printTree(tree) + case bl @ Block(stats, expr) => + printBlock(treeInfo.untypecheckedBlockBody(bl), expr) case Match(selector, cases) => /* Insert braces if match is inner @@ -900,12 +948,24 @@ trait Printers extends api.Printers { self: SymbolTable => printFunction(f)(printValueParams(vparams, inParentheses = printParentheses)) case Typed(expr, tp) => + def printTp = print("(", tp, ")") + tp match { + case EmptyTree | build.SyntacticEmptyTypeTree() => printTp + // case for untypechecked trees + case Annotated(annot, arg) if (expr ne null) && (arg ne null) && expr.equalsStructure(arg) => printTp // remove double arg - 5: 5: @unchecked + case tt: TypeTree if tt.original.isInstanceOf[Annotated] => printTp case Function(List(), EmptyTree) => print("(", expr, " _)") //func _ // parentheses required when (a match {}) : Type case _ => print("((", expr, "): ", tp, ")") } + // print only fun when targs are TypeTrees with empty original + case TypeApply(fun, targs) => + if (targs.exists(emptyTree(_))) { + print(fun) + } else super.printTree(tree) + case Apply(fun, vargs) => tree match { // processing methods ending on colons (x \: list) @@ -918,20 +978,48 @@ trait Printers extends api.Printers { self: SymbolTable => case _ => super.printTree(tree) } + case UnApply(fun, args) => + fun match { + case treeInfo.Unapplied(body) => + body match { + case Select(qual, name) if name == nme.unapply => print(qual) + case TypeApply(Select(qual, name), args) if name == nme.unapply || name == nme.unapplySeq => + print(TypeApply(qual, args)) + case _ => print(body) + } + case _ => print(fun) + } + printRow(args, "(", ", ", ")") + case st @ Super(This(qual), mix) => - printSuper(st, printedName(qual)) + printSuper(st, printedName(qual), checkSymbol = false) case th @ This(qual) => - printThis(th, printedName(qual)) + if (tree.hasExistingSymbol && tree.symbol.isPackage) print(tree.symbol.fullName) + else printThis(th, printedName(qual)) + + // remove this prefix from constructor invocation in typechecked trees: this.this -> this + case Select(This(_), name @ nme.CONSTRUCTOR) => print(printedName(name)) 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 Select(qual, name) => + def checkRootPackage(tr: Tree): Boolean = + (currentParent match { //check that Select is not for package def name + case Some(_: PackageDef) => false + case _ => true + }) && (tr match { // check that Select contains package + case Select(q, _) => checkRootPackage(q) + case _: Ident | _: This => val sym = tr.symbol + tr.hasExistingSymbol && sym.isPackage && sym.name != nme.ROOTPKG + case _ => false + }) + + if (printRootPkg && checkRootPackage(tree)) print(s"${printedName(nme.ROOTPKG)}.") + val printParentheses = needsParentheses(qual)(insideAnnotated = false) || isIntLitWithDecodedOp(qual, name) + if (printParentheses) print("(", resolveSelect(qual), ").", printedName(name)) + else print(resolveSelect(qual), ".", printedName(name)) case id @ Ident(name) => if (name.nonEmpty) { @@ -971,6 +1059,9 @@ trait Printers extends api.Printers { self: SymbolTable => case SelectFromTypeTree(qualifier, selector) => print("(", qualifier, ")#", blankForOperatorName(selector), printedName(selector)) + case tt: TypeTree => + if (!emptyTree(tt)) print(tt.original) + 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 @@ -996,7 +1087,6 @@ trait Printers extends api.Printers { self: SymbolTable => case tree => super.printTree(tree) } - parentsStack.pop() } } @@ -1004,7 +1094,9 @@ trait Printers extends api.Printers { self: SymbolTable => def xprintTree(treePrinter: TreePrinter, tree: Tree) = treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")")) - def newCodePrinter(writer: PrintWriter): TreePrinter = new ParsedTreePrinter(writer) + def newCodePrinter(writer: PrintWriter, tree: Tree, printRootPkg: Boolean): TreePrinter = + new CodePrinter(writer, printRootPkg) + 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/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala index 087d4186be..ea230a215b 100644 --- a/src/reflect/scala/reflect/internal/ReificationSupport.scala +++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala @@ -237,7 +237,9 @@ trait ReificationSupport { self: SymbolTable => // undo gen.mkTemplate protected object UnMkTemplate { def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = { - val Template(parents, selfType, tbody) = templ + val Template(parents, selfType, _) = templ + val tbody = treeInfo.untypecheckedTemplBody(templ) + def result(ctorMods: Modifiers, vparamss: List[List[ValDef]], edefs: List[Tree], body: List[Tree]) = Some((parents, selfType, ctorMods, vparamss, edefs, body)) def indexOfCtor(trees: List[Tree]) = @@ -463,8 +465,8 @@ trait ReificationSupport { self: SymbolTable => else gen.mkBlock(stats) def unapply(tree: Tree): Option[List[Tree]] = tree match { - case self.Block(stats, SyntheticUnit()) => Some(stats) - case self.Block(stats, expr) => Some(stats :+ expr) + case bl @ self.Block(stats, SyntheticUnit()) => Some(treeInfo.untypecheckedBlockBody(bl)) + case bl @ self.Block(stats, expr) => Some(treeInfo.untypecheckedBlockBody(bl) :+ expr) case EmptyTree => Some(Nil) case _ if tree.isTerm => Some(tree :: Nil) case _ => None diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index b7df2e82cb..7cf749c048 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -405,6 +405,67 @@ abstract class TreeInfo { case _ => false } + /** Does the tree have a structure similar to typechecked trees? */ + private[internal] def detectTypecheckedTree(tree: Tree) = + tree.hasExistingSymbol || tree.exists { + case dd: DefDef => dd.mods.hasAccessorFlag || dd.mods.isSynthetic // for untypechecked trees + case md: MemberDef => md.hasExistingSymbol + case _ => false + } + + /** Recover template body to parsed state */ + private[internal] def untypecheckedTemplBody(templ: Template) = + untypecheckedTreeBody(templ, templ.body) + + /** Recover block body to parsed state */ + private[internal] def untypecheckedBlockBody(block: Block) = + untypecheckedTreeBody(block, block.stats) + + /** Recover tree body to parsed state */ + private[internal] def untypecheckedTreeBody(tree: Tree, tbody: List[Tree]) = { + def filterBody(body: List[Tree]) = body filter { + case _: ValDef | _: TypeDef => true + // keep valdef or getter for val/var + case dd: DefDef if dd.mods.hasAccessorFlag => !nme.isSetterName(dd.name) && !tbody.exists { + case vd: ValDef => dd.name == vd.name.dropLocal + case _ => false + } + case md: MemberDef => !md.mods.isSynthetic + case tree => true + } + + def lazyValDefRhs(body: Tree) = + body match { + case Block(List(Assign(_, rhs)), _) => rhs + case _ => body + } + + def recoverBody(body: List[Tree]) = body map { + case vd @ ValDef(vmods, vname, _, vrhs) if nme.isLocalName(vname) => + tbody find { + case dd: DefDef => dd.name == vname.dropLocal + case _ => false + } map { dd => + val DefDef(dmods, dname, _, _, _, drhs) = dd + // get access flags from DefDef + val vdMods = (vmods &~ Flags.AccessFlags) | (dmods & Flags.AccessFlags).flags + // for most cases lazy body should be taken from accessor DefDef + val vdRhs = if (vmods.isLazy) lazyValDefRhs(drhs) else vrhs + copyValDef(vd)(mods = vdMods, name = dname, rhs = vdRhs) + } getOrElse (vd) + // for abstract and some lazy val/vars + case dd @ DefDef(mods, name, _, _, tpt, rhs) if mods.hasAccessorFlag => + // transform getter mods to field + val vdMods = (if (!mods.hasStableFlag) mods | Flags.MUTABLE else mods &~ Flags.STABLE) &~ Flags.ACCESSOR + ValDef(vdMods, name, tpt, rhs) + case tr => tr + } + + if (detectTypecheckedTree(tree)) { + recoverBody(filterBody(tbody)) + } else tbody + } + /** The first constructor definitions in `stats` */ def firstConstructor(stats: List[Tree]): Tree = stats find { case x: DefDef => nme.isConstructorName(x.name) diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 7a6862a770..9dc4baee32 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1685,10 +1685,12 @@ trait Trees extends api.Trees { // this is necessary to avoid crashes like https://github.com/scalamacros/paradise/issues/1 // when someone tries to c.typecheck a naked MemberDef - def wrappingIntoTerm(tree: Tree)(op: Tree => Tree): Tree = { - op(build.SyntacticBlock(tree :: Nil)) match { - case build.SyntacticBlock(tree :: Nil) => tree - case tree => tree + def wrappingIntoTerm(tree0: Tree)(op: Tree => Tree): Tree = { + val neededWrapping = !tree0.isTerm + val tree1 = build.SyntacticBlock(tree0 :: Nil) + op(tree1) match { + case Block(tree2 :: Nil, Literal(Constant(()))) if neededWrapping => tree2 + case tree2 => tree2 } } diff --git a/test/files/run/t7185.check b/test/files/run/t7185.check index 2b4adf36b4..ebf85b731f 100644 --- a/test/files/run/t7185.check +++ b/test/files/run/t7185.check @@ -24,7 +24,9 @@ tree: reflect.runtime.universe.Apply = scala> {val tb = reflect.runtime.currentMirror.mkToolBox(); tb.typecheck(tree): Any} res0: Any = { - $read.O.apply() + { + $read.O.apply() + } } scala> diff --git a/test/files/scalacheck/quasiquotes/TypecheckedProps.scala b/test/files/scalacheck/quasiquotes/TypecheckedProps.scala index 8b1cb6cc49..432c0959c9 100644 --- a/test/files/scalacheck/quasiquotes/TypecheckedProps.scala +++ b/test/files/scalacheck/quasiquotes/TypecheckedProps.scala @@ -65,7 +65,7 @@ object TypecheckedProps extends QuasiquoteProperties("typechecked") { } property("extract UnApply (2)") = test { - val q"object $_ { $_; $_; $m }" = typecheck(q""" + val q"object $_ { $_; $m }" = typecheck(q""" object Test { case class Cell(val x: Int) new Cell(0) match { case Cell(v) => v } @@ -82,4 +82,74 @@ object TypecheckedProps extends QuasiquoteProperties("typechecked") { val q"val x: ${tq""} = 42" = typechecked val q"val x: ${t: Type} = 42" = typechecked } + + property("class with param (1)") = test { + val paramName = TermName("x") + val q"class $_($param)" = typecheck(q"class Test(val $paramName: Int)") + + assert(param.name == paramName) + } + + property("class with param (2)") = test { + val paramName = TermName("y") + val q"{class $_($param)}" = typecheck(q"class Test(val $paramName: Int = 3)") + + assert(param.name == paramName) + assert(param.rhs ≈ q"3") + } + + property("class with params") = test { + val pName1 = TermName("x1") + val pName2 = TermName("x2") + val q"{class $_($param1)(..$params2)}" = typecheck(q"class Test(val x0: Float)(val $pName1: Int = 3, $pName2: String)") + + val List(p1, p2, _*) = params2 + + assert(p1.name == pName1) + assert(p2.name == pName2) + assert(params2.size == 2) + } + + property("implicit class") = test { + val clName = TypeName("Test") + val paramName = TermName("x") + val q"{implicit class $name($param)}" = typecheck(q"implicit class $clName(val $paramName: String)") + + assert(name == clName) + assert(param.name == paramName) + } + + property("block with lazy") = test { + val lazyName = TermName("x") + val lazyRhsVal = 42 + val lazyRhs = Literal(Constant(lazyRhsVal)) + val q"{lazy val $pname = $rhs}" = typecheck(q"{lazy val $lazyName = $lazyRhsVal}") + + assert(pname == lazyName) + assert(rhs ≈ lazyRhs) + } + + property("class with lazy") = test { + val clName = TypeName("Test") + val paramName = TermName("x") + val q"class $name{lazy val $pname = $_}" = typecheck(q"class $clName {lazy val $paramName = 42}") + + assert(name == clName) + assert(pname == paramName) + } + + property("case class with object") = test { + val defName = TermName("z") + val defRhsVal = 42 + val defRhs = Literal(Constant(defRhsVal)) + val q"object $_{ $_; object $_ extends ..$_ {def $name = $rhs} }" = + typecheck(q""" + object Test{ + case class C(x: Int) { def y = x }; + object C { def $defName = $defRhsVal } + }""") + + assert(name == defName) + assert(rhs ≈ defRhs) + } } diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala index 9fec112c99..62cb401aa9 100644 --- a/test/junit/scala/reflect/internal/PrintersTest.scala +++ b/test/junit/scala/reflect/internal/PrintersTest.scala @@ -821,4 +821,4 @@ // |case class X(x: Int, s: String) { // | def y = "test" // |}""", q"""case class X(x: Int, s: String){ def y = "test" }""") -// } +// }
\ No newline at end of file |