summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-01-29 01:55:46 -0800
committerJason Zaugg <jzaugg@gmail.com>2014-01-29 01:55:46 -0800
commit4506acba688e80a4f778e495a74e7a50f83c4e1b (patch)
treeb05a731dde14ce49f344260ceef2023cd973e646
parent057adc70346414c10273f58fcd44114bf0672933 (diff)
parent8e9862473abd03bded2d3afa60c777099f7872c5 (diff)
downloadscala-4506acba688e80a4f778e495a74e7a50f83c4e1b.tar.gz
scala-4506acba688e80a4f778e495a74e7a50f83c4e1b.tar.bz2
scala-4506acba688e80a4f778e495a74e7a50f83c4e1b.zip
Merge pull request #3374 from densh/si/6844-8076
SI-6844 SI-8076 improve handling of function parameters in quasiquotes
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala105
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala14
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala7
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala11
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala16
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala51
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala12
-rw-r--r--test/files/neg/quasiquotes-syntax-error-position.check5
-rw-r--r--test/files/neg/quasiquotes-syntax-error-position.scala3
-rw-r--r--test/files/neg/t6844.check6
-rw-r--r--test/files/neg/t6844.scala5
-rw-r--r--test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala15
-rw-r--r--test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala31
13 files changed, 194 insertions, 87 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 137fc79004..23a2e0b37f 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2137,8 +2137,6 @@ self =>
/* -------- PARAMETERS ------------------------------------------- */
- def allowTypelessParams = false
-
/** {{{
* ParamClauses ::= {ParamClause} [[nl] `(' implicit Params `)']
* ParamClause ::= [nl] `(' [Params] `)'
@@ -2153,56 +2151,6 @@ self =>
def paramClauses(owner: Name, contextBounds: List[Tree], ofCaseClass: Boolean): List[List[ValDef]] = {
var implicitmod = 0
var caseParam = ofCaseClass
- def param(): ValDef = {
- val start = in.offset
- val annots = annotations(skipNewLines = false)
- var mods = Modifiers(Flags.PARAM)
- if (owner.isTypeName) {
- mods = modifiers() | Flags.PARAMACCESSOR
- if (mods.isLazy) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", skipIt = false)
- in.token match {
- case v @ (VAL | VAR) =>
- mods = mods withPosition (in.token.toLong, tokenRange(in))
- if (v == VAR) mods |= Flags.MUTABLE
- in.nextToken()
- case _ =>
- if (mods.flags != Flags.PARAMACCESSOR) accept(VAL)
- if (!caseParam) mods |= Flags.PrivateLocal
- }
- if (caseParam) mods |= Flags.CASEACCESSOR
- }
- val nameOffset = in.offset
- val name = ident()
- var bynamemod = 0
- val tpt =
- if (((settings.YmethodInfer && !owner.isTypeName) || allowTypelessParams) && in.token != COLON) {
- TypeTree()
- } else { // XX-METHOD-INFER
- accept(COLON)
- if (in.token == ARROW) {
- if (owner.isTypeName && !mods.hasLocalFlag)
- syntaxError(
- in.offset,
- (if (mods.isMutable) "`var'" else "`val'") +
- " parameters may not be call-by-name", skipIt = false)
- else if (implicitmod != 0)
- syntaxError(
- in.offset,
- "implicit parameters may not be call-by-name", skipIt = false)
- else bynamemod = Flags.BYNAMEPARAM
- }
- paramType()
- }
- val default =
- if (in.token == EQUALS) {
- in.nextToken()
- mods |= Flags.DEFAULTPARAM
- expr()
- } else EmptyTree
- atPos(start, if (name == nme.ERROR) start else nameOffset) {
- ValDef((mods | implicitmod.toLong | bynamemod) withAnnotations annots, name.toTermName, tpt, default)
- }
- }
def paramClause(): List[ValDef] = {
if (in.token == RPAREN)
return Nil
@@ -2211,7 +2159,7 @@ self =>
in.nextToken()
implicitmod = Flags.IMPLICIT
}
- commaSeparated(param())
+ commaSeparated(param(owner, implicitmod, caseParam ))
}
val vds = new ListBuffer[List[ValDef]]
val start = in.offset
@@ -2259,6 +2207,57 @@ self =>
}
}
+ def param(owner: Name, implicitmod: Int, caseParam: Boolean): ValDef = {
+ val start = in.offset
+ val annots = annotations(skipNewLines = false)
+ var mods = Modifiers(Flags.PARAM)
+ if (owner.isTypeName) {
+ mods = modifiers() | Flags.PARAMACCESSOR
+ if (mods.isLazy) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", skipIt = false)
+ in.token match {
+ case v @ (VAL | VAR) =>
+ mods = mods withPosition (in.token.toLong, tokenRange(in))
+ if (v == VAR) mods |= Flags.MUTABLE
+ in.nextToken()
+ case _ =>
+ if (mods.flags != Flags.PARAMACCESSOR) accept(VAL)
+ if (!caseParam) mods |= Flags.PrivateLocal
+ }
+ if (caseParam) mods |= Flags.CASEACCESSOR
+ }
+ val nameOffset = in.offset
+ val name = ident()
+ var bynamemod = 0
+ val tpt =
+ if ((settings.YmethodInfer && !owner.isTypeName) && in.token != COLON) {
+ TypeTree()
+ } else { // XX-METHOD-INFER
+ accept(COLON)
+ if (in.token == ARROW) {
+ if (owner.isTypeName && !mods.hasLocalFlag)
+ syntaxError(
+ in.offset,
+ (if (mods.isMutable) "`var'" else "`val'") +
+ " parameters may not be call-by-name", skipIt = false)
+ else if (implicitmod != 0)
+ syntaxError(
+ in.offset,
+ "implicit parameters may not be call-by-name", skipIt = false)
+ else bynamemod = Flags.BYNAMEPARAM
+ }
+ paramType()
+ }
+ val default =
+ if (in.token == EQUALS) {
+ in.nextToken()
+ mods |= Flags.DEFAULTPARAM
+ expr()
+ } else EmptyTree
+ atPos(start, if (name == nme.ERROR) start else nameOffset) {
+ ValDef((mods | implicitmod.toLong | bynamemod) withAnnotations annots, name.toTermName, tpt, default)
+ }
+ }
+
/** {{{
* TypeParamClauseOpt ::= [TypeParamClause]
* TypeParamClause ::= `[' VariantTypeParam {`,' VariantTypeParam} `]']
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index c817b5122f..fcb8734644 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -80,8 +80,20 @@ trait Parsers { self: Quasiquotes =>
}
import treeBuilder.{global => _, unit => _, _}
+ def quasiquoteParam(name: Name, flags: FlagSet = NoFlags) =
+ ValDef(Modifiers(flags), name.toTermName, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree)
+
// q"def foo($x)"
- override def allowTypelessParams = true
+ override def param(owner: Name, implicitmod: Int, caseParam: Boolean): ValDef =
+ if (isHole && lookingAhead { in.token == COMMA || in.token == RPAREN }) {
+ quasiquoteParam(ident(), implicitmod)
+ } else super.param(owner, implicitmod, caseParam)
+
+ // q"($x) => ..." && q"class X { selfie => }
+ override def convertToParam(tree: Tree): ValDef = tree match {
+ case Ident(name) if isHole(name) => quasiquoteParam(name)
+ case _ => super.convertToParam(tree)
+ }
// q"foo match { case $x }"
override def caseClause(): CaseDef =
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index bdb44ad9a2..5669ec731f 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -95,7 +95,6 @@ trait Placeholders { self: Quasiquotes =>
case Ident(name) => name
case Bind(name, Ident(nme.WILDCARD)) => name
case TypeDef(_, name, List(), TypeBoundsTree(EmptyTree, EmptyTree)) => name
- case ValDef(_, name, TypeTree(), EmptyTree) => name
}
}
@@ -111,6 +110,12 @@ trait Placeholders { self: Quasiquotes =>
}
}
+ object ParamPlaceholder extends HolePlaceholder {
+ def matching = {
+ case ValDef(_, name, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree) => name
+ }
+ }
+
object TuplePlaceholder {
def unapply(tree: Tree): Option[List[Tree]] = tree match {
case Apply(Ident(nme.QUASIQUOTE_TUPLE), args) => Some(args)
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index 45bc2d776c..273245f7bd 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -137,6 +137,7 @@ trait Reifiers { self: Quasiquotes =>
case RefineStatPlaceholder(hole) => reifyRefineStat(hole)
case EarlyDefPlaceholder(hole) => reifyEarlyDef(hole)
case PackageStatPlaceholder(hole) => reifyPackageStat(hole)
+ case ParamPlaceholder(hole) => hole.tree
// for enumerators are checked not during splicing but during
// desugaring of the for loop in SyntacticFor & SyntacticForYield
case ForEnumPlaceholder(hole) => hole.tree
@@ -159,8 +160,12 @@ trait Reifiers { self: Quasiquotes =>
reifyBuildCall(nme.SyntacticObjectDef, mods, name, earlyDefs, parents, selfdef, body)
case SyntacticNew(earlyDefs, parents, selfdef, body) =>
reifyBuildCall(nme.SyntacticNew, earlyDefs, parents, selfdef, body)
- case SyntacticDefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs)
+ case SyntacticDefDef(mods, name, tparams, build.ImplicitParams(vparamss, implparams), tpt, rhs) =>
+ if (implparams.nonEmpty)
+ mirrorBuildCall(nme.SyntacticDefDef, reify(mods), reify(name), reify(tparams),
+ reifyBuildCall(nme.ImplicitParams, vparamss, implparams), reify(tpt), reify(rhs))
+ else
+ reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs)
case SyntacticValDef(mods, name, tpt, rhs) if tree != noSelfType =>
reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs)
case SyntacticVarDef(mods, name, tpt, rhs) =>
@@ -313,6 +318,8 @@ trait Reifiers { self: Quasiquotes =>
case EarlyDefPlaceholder(h @ Hole(_, DotDot)) => reifyEarlyDef(h)
case PackageStatPlaceholder(h @ Hole(_, DotDot)) => reifyPackageStat(h)
case ForEnumPlaceholder(Hole(tree, DotDot)) => tree
+ case ParamPlaceholder(Hole(tree, DotDot)) => tree
+ case List(ParamPlaceholder(Hole(tree, DotDotDot))) => tree
case List(Placeholder(Hole(tree, DotDotDot))) => tree
} {
reify(_)
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
index 3a69390bcf..3bcf751ace 100644
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ b/src/reflect/scala/reflect/api/BuildUtils.scala
@@ -96,6 +96,13 @@ private[reflect] trait BuildUtils { self: Universe =>
def freshTypeName(prefix: String): TypeName
+ val ImplicitParams: ImplicitParamsExtractor
+
+ trait ImplicitParamsExtractor {
+ def apply(paramss: List[List[ValDef]], implparams: List[ValDef]): List[List[ValDef]]
+ def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])]
+ }
+
val ScalaDot: ScalaDotExtractor
trait ScalaDotExtractor {
@@ -128,8 +135,8 @@ private[reflect] trait BuildUtils { self: Universe =>
trait SyntacticClassDefExtractor {
def apply(mods: Modifiers, name: TypeName, tparams: List[Tree],
- constrMods: Modifiers, vparamss: List[List[Tree]], earlyDefs: List[Tree],
- parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef
+ constrMods: Modifiers, vparamss: List[List[Tree]],
+ earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef
def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]],
List[Tree], List[Tree], ValDef, List[Tree])]
}
@@ -199,9 +206,10 @@ private[reflect] trait BuildUtils { self: Universe =>
val SyntacticDefDef: SyntacticDefDefExtractor
trait SyntacticDefDefExtractor {
- def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef
+ def apply(mods: Modifiers, name: TermName, tparams: List[Tree],
+ vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef
- def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[List[ValDef]], Tree, Tree)]
+ def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)]
}
val SyntacticValDef: SyntacticValDefExtractor
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index 16bb3e5989..6106339324 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -73,18 +73,25 @@ trait BuildUtils { self: SymbolTable =>
def mkAnnotation(trees: List[Tree]): List[Tree] = trees.map(mkAnnotation)
- def mkVparamss(argss: List[List[Tree]]): List[List[ValDef]] = argss.map(_.map(mkParam))
+ def mkParam(argss: List[List[Tree]], extraFlags: FlagSet = NoFlags): List[List[ValDef]] =
+ argss.map { args => args.map { mkParam(_, extraFlags) } }
- def mkParam(tree: Tree): ValDef = tree match {
+ def mkParam(tree: Tree, extraFlags: FlagSet): ValDef = tree match {
+ case Typed(Ident(name: TermName), tpt) =>
+ mkParam(ValDef(NoMods, name, tpt, EmptyTree), extraFlags)
case vd: ValDef =>
- var newmods = (vd.mods | PARAM) & (~DEFERRED)
+ var newmods = vd.mods & (~DEFERRED)
if (vd.rhs.nonEmpty) newmods |= DEFAULTPARAM
- copyValDef(vd)(mods = newmods)
+ copyValDef(vd)(mods = newmods | extraFlags)
case _ =>
- throw new IllegalArgumentException(s"$tree is not valid represenation of function parameter, " +
+ throw new IllegalArgumentException(s"$tree is not valid represenation of a parameter, " +
"""consider reformatting it into q"val $name: $T = $default" shape""")
}
+ def mkImplicitParam(args: List[Tree]): List[ValDef] = args.map(mkImplicitParam)
+
+ def mkImplicitParam(tree: Tree): ValDef = mkParam(tree, IMPLICIT | PARAM)
+
def mkTparams(tparams: List[Tree]): List[TypeDef] =
tparams.map {
case td: TypeDef => copyTypeDef(td)(mods = (td.mods | PARAM) & (~DEFERRED))
@@ -142,6 +149,16 @@ trait BuildUtils { self: SymbolTable =>
protected implicit def fresh: FreshNameCreator = self.currentFreshNameCreator
+ object ImplicitParams extends ImplicitParamsExtractor {
+ def apply(paramss: List[List[ValDef]], implparams: List[ValDef]): List[List[ValDef]] =
+ if (implparams.nonEmpty) paramss :+ mkImplicitParam(implparams) else paramss
+
+ def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] = vparamss match {
+ case init :+ (last @ (initlast :: _)) if initlast.mods.isImplicit => Some((init, last))
+ case _ => Some((vparamss, Nil))
+ }
+ }
+
object FlagsRepr extends FlagsReprExtractor {
def apply(bits: Long): FlagSet = bits
def unapply(flags: Long): Some[Long] = Some(flags)
@@ -241,14 +258,10 @@ trait BuildUtils { self: SymbolTable =>
object SyntacticClassDef extends SyntacticClassDefExtractor {
def apply(mods: Modifiers, name: TypeName, tparams: List[Tree],
- constrMods: Modifiers, vparamss: List[List[Tree]], earlyDefs: List[Tree],
- parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = {
+ constrMods: Modifiers, vparamss: List[List[Tree]],
+ earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = {
val extraFlags = PARAMACCESSOR | (if (mods.isCase) CASEACCESSOR else 0L)
- val vparamss0 = vparamss.map { _.map {
- case vd: ValDef => copyValDef(vd)(mods = (vd.mods | extraFlags) & (~DEFERRED))
- case tree => throw new IllegalArgumentException(s"$tree is not valid representation of class parameter, " +
- """consider reformatting it into q"val $name: $T = $default" shape""")
- } }
+ val vparamss0 = mkParam(vparamss, extraFlags)
val tparams0 = mkTparams(tparams)
val parents0 = gen.mkParents(mods,
if (mods.isCase) parents.filter {
@@ -423,7 +436,7 @@ trait BuildUtils { self: SymbolTable =>
object SyntacticFunction extends SyntacticFunctionExtractor {
def apply(params: List[Tree], body: Tree): Tree = {
- val params0 :: Nil = mkVparamss(params :: Nil)
+ val params0 :: Nil = mkParam(params :: Nil, PARAM)
require(params0.forall { _.rhs.isEmpty }, "anonymous functions don't support parameters with default values")
Function(params0, body)
}
@@ -450,11 +463,15 @@ trait BuildUtils { self: SymbolTable =>
}
object SyntacticDefDef extends SyntacticDefDefExtractor {
- def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef =
- DefDef(mods, name, mkTparams(tparams), mkVparamss(vparamss), tpt, rhs)
+ def apply(mods: Modifiers, name: TermName, tparams: List[Tree],
+ vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef = {
+ val vparamss0 = mkParam(vparamss, PARAM)
+ DefDef(mods, name, mkTparams(tparams), vparamss0, tpt, rhs)
+ }
- def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[List[ValDef]], Tree, Tree)] = tree match {
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) => Some((mods, name, tparams, vparamss, tpt, rhs))
+ def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)] = tree match {
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ Some((mods, name, tparams, vparamss, tpt, rhs))
case _ => None
}
}
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 256d5759fa..a46cd05efa 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -250,12 +250,13 @@ trait StdNames {
final val Quasiquote: NameType = "Quasiquote"
// quasiquote-specific names
- final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$"
- final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
- final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$"
- final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$"
final val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$"
+ final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$"
+ final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$"
final val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$"
+ final val QUASIQUOTE_PARAM: NameType = "$quasiquote$param$"
+ final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$"
+ final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
// Annotation simple names, used in Namer
final val BeanPropertyAnnot: NameType = "BeanProperty"
@@ -577,6 +578,7 @@ trait StdNames {
val Flag : NameType = "Flag"
val FlagsRepr: NameType = "FlagsRepr"
val Ident: NameType = "Ident"
+ val ImplicitParams: NameType = "ImplicitParams"
val Import: NameType = "Import"
val Literal: NameType = "Literal"
val LiteralAnnotArg: NameType = "LiteralAnnotArg"
@@ -705,9 +707,9 @@ trait StdNames {
val materializeTypeTag: NameType = "materializeTypeTag"
val moduleClass : NameType = "moduleClass"
val mkAnnotation: NameType = "mkAnnotation"
- val mkRefineStat: NameType = "mkRefineStat"
val mkEarlyDef: NameType = "mkEarlyDef"
val mkPackageStat: NameType = "mkPackageStat"
+ val mkRefineStat: NameType = "mkRefineStat"
val ne: NameType = "ne"
val newArray: NameType = "newArray"
val newFreeTerm: NameType = "newFreeTerm"
diff --git a/test/files/neg/quasiquotes-syntax-error-position.check b/test/files/neg/quasiquotes-syntax-error-position.check
index 25e5b8d75a..14fef16e01 100644
--- a/test/files/neg/quasiquotes-syntax-error-position.check
+++ b/test/files/neg/quasiquotes-syntax-error-position.check
@@ -29,4 +29,7 @@ quasiquotes-syntax-error-position.scala:13: error: end of quote expected but 'ca
quasiquotes-syntax-error-position.scala:14: error: ')' expected but end of quote found.
pq"$a(bar"
^
-10 errors found
+quasiquotes-syntax-error-position.scala:15: error: ':' expected but ')' found.
+ q"def foo(x)"
+ ^
+11 errors found
diff --git a/test/files/neg/quasiquotes-syntax-error-position.scala b/test/files/neg/quasiquotes-syntax-error-position.scala
index b97af52cfc..7b1d66ba00 100644
--- a/test/files/neg/quasiquotes-syntax-error-position.scala
+++ b/test/files/neg/quasiquotes-syntax-error-position.scala
@@ -12,4 +12,5 @@ object test extends App {
tq"$t => $t $t]"
cq"pattern => body ; case pattern2 =>"
pq"$a(bar"
-} \ No newline at end of file
+ q"def foo(x)"
+}
diff --git a/test/files/neg/t6844.check b/test/files/neg/t6844.check
new file mode 100644
index 0000000000..1fc2485520
--- /dev/null
+++ b/test/files/neg/t6844.check
@@ -0,0 +1,6 @@
+t6844.scala:4: error: type mismatch;
+ found : reflect.runtime.universe.TermName
+ required: reflect.runtime.universe.Tree
+ q"def foo($x)"
+ ^
+one error found
diff --git a/test/files/neg/t6844.scala b/test/files/neg/t6844.scala
new file mode 100644
index 0000000000..809d9d0f98
--- /dev/null
+++ b/test/files/neg/t6844.scala
@@ -0,0 +1,5 @@
+import scala.reflect.runtime.universe._
+object Test extends App {
+ val x = TermName("x")
+ q"def foo($x)"
+}
diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
index 2af656c7c9..3166eb7a99 100644
--- a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
@@ -7,6 +7,7 @@ object DefinitionConstructionProps
with TraitConstruction
with TypeDefConstruction
with ValDefConstruction
+ with DefConstruction
with PackageConstruction {
property("SI-6842") = test {
val x: Tree = q"val x: Int"
@@ -349,4 +350,16 @@ trait PackageConstruction { self: QuasiquoteProperties =>
assertEqAst(q"package object foo extends { ..$edefs } with Any",
"package object foo extends { val x = 1; type I = Int } with Any")
}
-} \ No newline at end of file
+}
+
+trait DefConstruction { self: QuasiquoteProperties =>
+ property("construct implicit args (1)") = test {
+ val x = q"val x: Int"
+ assertEqAst(q"def foo(implicit $x) = x", "def foo(implicit x: Int) = x")
+ }
+
+ property("construct implicit args (2)") = test {
+ val xs = q"val x1: Int" :: q"val x2: Long" :: Nil
+ assertEqAst(q"def foo(implicit ..$xs) = x1 + x2", "def foo(implicit x1: Int, x2: Long) = x1 + x2")
+ }
+}
diff --git a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala
index 94465930ed..209fe9bbeb 100644
--- a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala
@@ -8,6 +8,7 @@ object DefinitionDeconstructionProps
with ObjectDeconstruction
with ModsDeconstruction
with ValVarDeconstruction
+ with DefDeconstruction
with PackageDeconstruction
trait TraitDeconstruction { self: QuasiquoteProperties =>
@@ -179,4 +180,32 @@ trait PackageDeconstruction { self: QuasiquoteProperties =>
matches("package object foo extends { val early = 1 } with daddy")
assertThrows[MatchError] { matches("object foo") }
}
-} \ No newline at end of file
+}
+
+trait DefDeconstruction { self: QuasiquoteProperties =>
+ property("exhaustive def matcher") = test {
+ def matches(line: String) = {
+ val t = parse(line)
+ val q"$mods0 def $name0[..$targs0](...$argss0): $restpe0 = $body0" = t
+ val q"$mods1 def $name1[..$targs1](...$argss1)(implicit ..$impl1): $restpe1 = $body1" = t
+ }
+ matches("def foo = foo")
+ matches("implicit def foo: Int = 2")
+ matches("def foo[T](x: T): T = x")
+ matches("def foo[A: B] = implicitly[B[A]]")
+ matches("private def foo = 0")
+ matches("def foo[A <% B] = null")
+ matches("def foo(one: One)(two: Two) = (one, two)")
+ matches("def foo[T](args: T*) = args.toList")
+ }
+
+ property("extract implicit arg list (1)") = test {
+ val q"def foo(...$argss)(implicit ..$impl)" = q"def foo(x: Int)(implicit y: Int)"
+ assert(impl ≈ List(q"${Modifiers(IMPLICIT | PARAM)} val y: Int"))
+ }
+
+ property("extract implicit arg list (2)") = test {
+ val q"def foo(...$argss)(implicit ..$impl)" = q"def foo(x: Int)"
+ assert(impl.isEmpty)
+ }
+}