summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala8
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala15
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala6
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala27
-rw-r--r--src/reflect/scala/reflect/api/Internals.scala2
-rw-r--r--src/reflect/scala/reflect/internal/ReificationSupport.scala45
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala2
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/DocFactory.scala2
-rw-r--r--test/files/neg/quasiquotes-syntax-error-position.check14
-rw-r--r--test/files/neg/quasiquotes-syntax-error-position.scala5
-rw-r--r--test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala11
-rw-r--r--test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala14
-rw-r--r--test/files/scalacheck/quasiquotes/ErrorProps.scala12
-rw-r--r--test/files/scalacheck/quasiquotes/TermConstructionProps.scala19
-rw-r--r--test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala24
16 files changed, 149 insertions, 58 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 3542fe5945..9e631febee 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -3096,10 +3096,6 @@ self =>
stats ++= importClause()
acceptStatSepOpt()
}
- else if (isExprIntro) {
- stats += statement(InBlock)
- if (!isCaseDefEnd) acceptStatSep()
- }
else if (isDefIntro || isLocalModifier || isAnnotation) {
if (in.token == IMPLICIT) {
val start = in.skipToken()
@@ -3110,6 +3106,10 @@ self =>
}
acceptStatSepOpt()
}
+ else if (isExprIntro) {
+ stats += statement(InBlock)
+ if (!isCaseDefEnd) acceptStatSep()
+ }
else if (isStatSep) {
in.nextToken()
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index 3b93a8933d..b68022afd9 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -22,7 +22,8 @@ trait Parsers { self: Quasiquotes =>
def parse(code: String): Tree = {
try {
val file = new BatchSourceFile(nme.QUASIQUOTE_FILE, code)
- new QuasiquoteParser(file).parseRule(entryPoint)
+ val parser = new QuasiquoteParser(file)
+ parser.checkNoEscapingPlaceholders { parser.parseRule(entryPoint) }
} catch {
case mi: MalformedInput => c.abort(correspondingPosition(mi.offset), mi.msg)
}
@@ -30,15 +31,15 @@ trait Parsers { self: Quasiquotes =>
def correspondingPosition(offset: Int): Position = {
val posMapList = posMap.toList
- def containsOffset(start: Int, end: Int) = start <= offset && offset <= end
+ def containsOffset(start: Int, end: Int) = start <= offset && offset < end
def fallbackPosition = posMapList match {
case (pos1, (start1, end1)) :: _ if start1 > offset => pos1
- case _ :+ ((pos2, (start2, end2))) if offset > end2 => pos2.withPoint(pos2.point + (end2 - start2))
+ case _ :+ ((pos2, (start2, end2))) if end2 <= offset => pos2.withPoint(pos2.point + (end2 - start2))
}
posMapList.sliding(2).collect {
- case (pos1, (start1, end1)) :: _ if containsOffset(start1, end1) => (pos1, offset - start1)
- case (pos1, (_, end1)) :: (_, (start2, _)) :: _ if containsOffset(end1, start2) => (pos1, end1)
- case _ :: (pos2, (start2, end2)) :: _ if containsOffset(start2, end2) => (pos2, offset - start2)
+ case (pos1, (start1, end1)) :: _ if containsOffset(start1, end1) => (pos1, offset - start1)
+ case (pos1, (start1, end1)) :: (pos2, (start2, _)) :: _ if containsOffset(end1, start2) => (pos1, end1 - start1)
+ case _ :: (pos2, (start2, end2)) :: _ if containsOffset(start2, end2) => (pos2, offset - start2)
}.map { case (pos, offset) =>
pos.withPoint(pos.point + offset)
}.toList.headOption.getOrElse(fallbackPosition)
@@ -118,6 +119,8 @@ trait Parsers { self: Quasiquotes =>
override def isTemplateIntro: Boolean = super.isTemplateIntro || (isHole && lookingAhead { isTemplateIntro })
+ override def isDefIntro: Boolean = super.isDefIntro || (isHole && lookingAhead { isDefIntro })
+
override def isDclIntro: Boolean = super.isDclIntro || (isHole && lookingAhead { isDclIntro })
override def isStatSep(token: Int) = token == EOF || super.isStatSep(token)
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index 5986758c2b..b287971815 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -17,7 +17,7 @@ trait Placeholders { self: Quasiquotes =>
// Step 1: Transform Scala source with holes into vanilla Scala source
- lazy val posMap = mutable.ListMap[Position, (Int, Int)]()
+ lazy val posMap = mutable.LinkedHashMap[Position, (Int, Int)]()
lazy val code = {
val sb = new StringBuilder()
val sessionSuffix = randomUUID().toString.replace("-", "").substring(0, 8) + "$"
@@ -40,9 +40,7 @@ trait Placeholders { self: Quasiquotes =>
val iargs = method match {
case nme.apply => args
- case nme.unapply =>
- val (dummy @ Ident(nme.SELECTOR_DUMMY)) :: Nil = args
- internal.subpatterns(dummy).get
+ case nme.unapply => internal.subpatterns(args.head).get
case _ => global.abort("unreachable")
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index 61fb22bc73..5eae3b6e6f 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -151,21 +151,20 @@ trait Reifiers { self: Quasiquotes =>
mirrorCall(nme.This, tree)
case SyntacticTraitDef(mods, name, tparams, earlyDefs, parents, selfdef, body) =>
reifyBuildCall(nme.SyntacticTraitDef, mods, name, tparams, earlyDefs, parents, selfdef, body)
- case SyntacticClassDef(mods, name, tparams, constrmods, vparamss, earlyDefs, parents, selfdef, body) =>
- reifyBuildCall(nme.SyntacticClassDef, mods, name, tparams, constrmods, vparamss,
- earlyDefs, parents, selfdef, body)
+ case SyntacticClassDef(mods, name, tparams, constrmods, vparamss,
+ earlyDefs, parents, selfdef, body) =>
+ mirrorBuildCall(nme.SyntacticClassDef, reify(mods), reify(name), reify(tparams), reify(constrmods),
+ reifyVparamss(vparamss), reify(earlyDefs), reify(parents),
+ reify(selfdef), reify(body))
case SyntacticPackageObjectDef(name, earlyDefs, parents, selfdef, body) =>
reifyBuildCall(nme.SyntacticPackageObjectDef, name, earlyDefs, parents, selfdef, body)
case SyntacticObjectDef(mods, name, earlyDefs, parents, selfdef, body) =>
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, 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 SyntacticDefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ mirrorBuildCall(nme.SyntacticDefDef, reify(mods), reify(name), reify(tparams),
+ reifyVparamss(vparamss), reify(tpt), reify(rhs))
case SyntacticValDef(mods, name, tpt, rhs) if tree != noSelfType =>
reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs)
case SyntacticVarDef(mods, name, tpt, rhs) =>
@@ -202,10 +201,14 @@ trait Reifiers { self: Quasiquotes =>
// not to cause infinite recursion.
case block @ SyntacticBlock(stats) if block.isInstanceOf[Block] =>
reifyBuildCall(nme.SyntacticBlock, stats)
+ case SyntheticUnit() =>
+ reifyBuildCall(nme.SyntacticBlock, Nil)
case Try(block, catches, finalizer) =>
reifyBuildCall(nme.SyntacticTry, block, catches, finalizer)
case Match(selector, cases) =>
reifyBuildCall(nme.SyntacticMatch, selector, cases)
+ case CaseDef(pat, guard, body) if fillListHole.isDefinedAt(body) =>
+ mirrorCall(nme.CaseDef, reify(pat), reify(guard), mirrorBuildCall(nme.SyntacticBlock, fillListHole(body)))
// parser emits trees with scala package symbol to ensure
// that some names hygienically point to various scala package
// members; we need to preserve this symbol to preserve
@@ -266,6 +269,12 @@ trait Reifiers { self: Quasiquotes =>
def reifyPackageStat(hole: Hole) = reifyConstructionCheck(nme.mkPackageStat, hole)
+ def reifyVparamss(vparamss: List[List[ValDef]]) = {
+ val build.ImplicitParams(paramss, implparams) = vparamss
+ if (implparams.isEmpty) reify(paramss)
+ else reifyBuildCall(nme.ImplicitParams, paramss, implparams)
+ }
+
/** Splits list into a list of groups where subsequent elements are considered
* similar by the corresponding function.
*
diff --git a/src/reflect/scala/reflect/api/Internals.scala b/src/reflect/scala/reflect/api/Internals.scala
index 01700345d1..01f928ed61 100644
--- a/src/reflect/scala/reflect/api/Internals.scala
+++ b/src/reflect/scala/reflect/api/Internals.scala
@@ -581,7 +581,7 @@ trait Internals { self: Universe =>
val ImplicitParams: ImplicitParamsExtractor
trait ImplicitParamsExtractor {
- def apply(paramss: List[List[ValDef]], implparams: List[ValDef]): List[List[ValDef]]
+ def apply(paramss: List[List[Tree]], implparams: List[Tree]): List[List[Tree]]
def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])]
}
diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala
index ea230a215b..66ac4bc751 100644
--- a/src/reflect/scala/reflect/internal/ReificationSupport.scala
+++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala
@@ -94,7 +94,11 @@ trait ReificationSupport { 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 toStats(tree: Tree): List[Tree] = tree match {
+ case EmptyTree => Nil
+ case SyntacticBlock(stats) => stats
+ case _ => throw new IllegalArgumentException(s"can't flatten $tree")
+ }
def mkAnnotation(tree: Tree): Tree = tree match {
case SyntacticNew(Nil, SyntacticApplied(SyntacticTypeApplied(_, _), _) :: Nil, noSelfType, Nil) =>
@@ -106,14 +110,14 @@ trait ReificationSupport { self: SymbolTable =>
def mkAnnotation(trees: List[Tree]): List[Tree] = trees.map(mkAnnotation)
- def mkParam(argss: List[List[Tree]], extraFlags: FlagSet = NoFlags): List[List[ValDef]] =
- argss.map { args => args.map { mkParam(_, extraFlags) } }
+ def mkParam(argss: List[List[Tree]], extraFlags: FlagSet = NoFlags, excludeFlags: FlagSet = DEFERRED): List[List[ValDef]] =
+ argss.map { args => args.map { mkParam(_, extraFlags, excludeFlags) } }
- def mkParam(tree: Tree, extraFlags: FlagSet): ValDef = tree match {
+ def mkParam(tree: Tree, extraFlags: FlagSet, excludeFlags: FlagSet): ValDef = tree match {
case Typed(Ident(name: TermName), tpt) =>
- mkParam(ValDef(NoMods, name, tpt, EmptyTree), extraFlags)
+ mkParam(ValDef(NoMods, name, tpt, EmptyTree), extraFlags, excludeFlags)
case vd: ValDef =>
- var newmods = vd.mods & (~DEFERRED)
+ var newmods = vd.mods & (~excludeFlags)
if (vd.rhs.nonEmpty) newmods |= DEFAULTPARAM
copyValDef(vd)(mods = newmods | extraFlags)
case _ =>
@@ -123,7 +127,7 @@ trait ReificationSupport { self: SymbolTable =>
def mkImplicitParam(args: List[Tree]): List[ValDef] = args.map(mkImplicitParam)
- def mkImplicitParam(tree: Tree): ValDef = mkParam(tree, IMPLICIT | PARAM)
+ def mkImplicitParam(tree: Tree): ValDef = mkParam(tree, IMPLICIT | PARAM, NoFlags)
def mkTparams(tparams: List[Tree]): List[TypeDef] =
tparams.map {
@@ -183,7 +187,7 @@ trait ReificationSupport { 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]] =
+ def apply(paramss: List[List[Tree]], implparams: List[Tree]): List[List[Tree]] =
if (implparams.nonEmpty) paramss :+ mkImplicitParam(implparams) else paramss
def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] = vparamss match {
@@ -239,7 +243,7 @@ trait ReificationSupport { self: SymbolTable =>
def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = {
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]) =
@@ -296,7 +300,7 @@ trait ReificationSupport { self: SymbolTable =>
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 = mkParam(vparamss, extraFlags)
+ val vparamss0 = mkParam(vparamss, extraFlags, excludeFlags = DEFERRED | PARAM)
val tparams0 = mkTparams(tparams)
val parents0 = gen.mkParents(mods,
if (mods.isCase) parents.filter {
@@ -448,28 +452,25 @@ trait ReificationSupport { self: SymbolTable =>
* 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
+ * 1. Strips trailing synthetic units which are inserted by the
* compiler if the block ends with a definition rather
- * than an expression.
+ * than an expression or is empty.
*
- * 3. Matches non-block term trees and recognizes them as
+ * 2. 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.
+ * expressions as just expressions. The only exception is q""
+ * which is not considered to be a block.
*/
object SyntacticBlock extends SyntacticBlockExtractor {
- def apply(stats: List[Tree]): Tree =
- if (stats.isEmpty) EmptyTree
- else gen.mkBlock(stats)
+ def apply(stats: List[Tree]): Tree = gen.mkBlock(stats)
def unapply(tree: Tree): Option[List[Tree]] = tree match {
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
+ case SyntheticUnit() => Some(Nil)
+ case _ if tree.isTerm && tree.nonEmpty => Some(tree :: Nil)
+ case _ => None
}
}
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index f3467ff9f4..339923a061 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -580,6 +580,7 @@ trait StdNames {
val AnyVal: NameType = "AnyVal"
val Apply: NameType = "Apply"
val ArrayAnnotArg: NameType = "ArrayAnnotArg"
+ val CaseDef: NameType = "CaseDef"
val ClassInfoType: NameType = "ClassInfoType"
val ConstantType: NameType = "ConstantType"
val EmptyPackage: NameType = "EmptyPackage"
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index 6011289baf..9066c73393 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -452,7 +452,7 @@ abstract class TreeGen {
/** Create block of statements `stats` */
def mkBlock(stats: List[Tree]): Tree =
- if (stats.isEmpty) Literal(Constant(()))
+ if (stats.isEmpty) mkSyntheticUnit()
else if (!stats.last.isTerm) Block(stats, mkSyntheticUnit())
else if (stats.length == 1) stats.head
else Block(stats.init, stats.last)
diff --git a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
index 4607684c0d..dce52af56a 100644
--- a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
@@ -94,7 +94,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
val documentError: PartialFunction[Throwable, Unit] = {
case NoCompilerRunException =>
- reporter.info(null, "No documentation generated with unsucessful compiler run", force = false)
+ reporter.info(null, "No documentation generated with unsuccessful compiler run", force = false)
case _: ClassNotFoundException =>
()
}
diff --git a/test/files/neg/quasiquotes-syntax-error-position.check b/test/files/neg/quasiquotes-syntax-error-position.check
index fd55bd25b5..9fd6ce0417 100644
--- a/test/files/neg/quasiquotes-syntax-error-position.check
+++ b/test/files/neg/quasiquotes-syntax-error-position.check
@@ -32,4 +32,16 @@ quasiquotes-syntax-error-position.scala:14: error: ')' expected but end of quote
quasiquotes-syntax-error-position.scala:15: error: ':' expected but ')' found.
q"def foo(x)"
^
-11 errors found
+quasiquotes-syntax-error-position.scala:16: error: illegal start of simple expression
+ q"$a(])"
+ ^
+quasiquotes-syntax-error-position.scala:17: error: in XML literal: '>' expected instead of '$'
+ q"foo bar <xml$a>"
+ ^
+quasiquotes-syntax-error-position.scala:19: error: ';' expected but '<:' found.
+ q"val $x: $x <: $x"
+ ^
+quasiquotes-syntax-error-position.scala:20: error: '=' expected but '.' found.
+ q"def f ( $x ) . $x"
+ ^
+15 errors found
diff --git a/test/files/neg/quasiquotes-syntax-error-position.scala b/test/files/neg/quasiquotes-syntax-error-position.scala
index 7b1d66ba00..823fe9a551 100644
--- a/test/files/neg/quasiquotes-syntax-error-position.scala
+++ b/test/files/neg/quasiquotes-syntax-error-position.scala
@@ -13,4 +13,9 @@ object test extends App {
cq"pattern => body ; case pattern2 =>"
pq"$a(bar"
q"def foo(x)"
+ q"$a(])"
+ q"foo bar <xml$a>"
+ val x = q"x"
+ q"val $x: $x <: $x"
+ q"def f ( $x ) . $x"
}
diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
index fdb0d83277..69aef12668 100644
--- a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala
@@ -9,7 +9,7 @@ object DefinitionConstructionProps
with ValDefConstruction
with PatDefConstruction
with DefConstruction
- with PackageConstruction
+ with PackageConstruction
with ImportConstruction {
val x: Tree = q"val x: Int"
@@ -81,6 +81,15 @@ trait ClassConstruction { self: QuasiquoteProperties =>
assertEqAst(q" class C($privx)", " class C(x: Int) ")
assertEqAst(q"case class C($privx)", "case class C(private[this] val x: Int)")
}
+
+ property("SI-8333") = test {
+ assertEqAst(q"{ $NoMods class C }", "{ class C }")
+ }
+
+ property("SI-8332") = test {
+ val args = q"val a: Int; val b: Int"
+ assertEqAst(q"class C(implicit ..$args)", "class C(implicit val a: Int, val b: Int)")
+ }
}
trait TraitConstruction { self: QuasiquoteProperties =>
diff --git a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala
index 996ac65b36..af7f2164a0 100644
--- a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala
@@ -73,8 +73,11 @@ trait ClassDeconstruction { self: QuasiquoteProperties =>
property("exhaustive class matcher") = test {
def matches(line: String) {
- val q"""$classMods class $name[..$targs] $ctorMods(...$argss)
- extends { ..$early } with ..$parents { $self => ..$body }""" = parse(line)
+ val tree = parse(line)
+ val q"""$classMods0 class $name0[..$targs0] $ctorMods0(...$argss0)
+ extends { ..$early0 } with ..$parents0 { $self0 => ..$body0 }""" = tree
+ val q"""$classMods1 class $name1[..$targs1] $ctorMods1(...$argss1)(implicit ..$impl)
+ extends { ..$early1 } with ..$parents1 { $self1 => ..$body1 }""" = tree
}
matches("class Foo")
matches("class Foo[T]")
@@ -106,6 +109,13 @@ trait ClassDeconstruction { self: QuasiquoteProperties =>
Ident(TypeName("Int")), EmptyTree))), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(())))))))
}
}
+
+ property("SI-8332") = test {
+ val q"class C(implicit ..$args)" = q"class C(implicit i: I, j: J)"
+ val q"$imods val i: I" :: q"$jmods val j: J" :: Nil = args
+ assert(imods.hasFlag(IMPLICIT))
+ assert(jmods.hasFlag(IMPLICIT))
+ }
}
trait ModsDeconstruction { self: QuasiquoteProperties =>
diff --git a/test/files/scalacheck/quasiquotes/ErrorProps.scala b/test/files/scalacheck/quasiquotes/ErrorProps.scala
index d61119d98f..3d9b27de77 100644
--- a/test/files/scalacheck/quasiquotes/ErrorProps.scala
+++ b/test/files/scalacheck/quasiquotes/ErrorProps.scala
@@ -160,6 +160,18 @@ object ErrorProps extends QuasiquoteProperties("errors") {
q"$n"
""")
+ property("SI-8211: check unbound placeholder paremeters") = fails(
+ "unbound placeholder parameter",
+ """
+ q"_"
+ """)
+
+ property("SI-8211: check unbound wildcard types") = fails(
+ "unbound wildcard type",
+ """
+ tq"_"
+ """)
+
// // Make sure a nice error is reported in this case
// { import Flag._; val mods = NoMods; q"lazy $mods val x: Int" }
}
diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
index 10ce1604b1..fd4d2e9c4b 100644
--- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
@@ -103,7 +103,7 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") {
def blockInvariant(quote: Tree, trees: List[Tree]) =
quote ≈ (trees match {
- case Nil => q""
+ case Nil => q"{}"
case _ :+ last if !last.isTerm => Block(trees, q"()")
case head :: Nil => head
case init :+ last => Block(init, last)
@@ -277,11 +277,18 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") {
assert(stats ≈ List(q"def x = 2", q"()"))
}
- property("empty-tree as block") = test {
- val q"{ ..$stats1 }" = q" "
- assert(stats1.isEmpty)
- val stats2 = List.empty[Tree]
- assert(q"{ ..$stats2 }" ≈ q"")
+ property("empty-tree is not a block") = test {
+ assertThrows[MatchError] {
+ val q"{ ..$stats1 }" = q" "
+ }
+ }
+
+ property("empty block is synthetic unit") = test {
+ val q"()" = q"{}"
+ val q"{..$stats}" = q"{}"
+ assert(stats.isEmpty)
+ assertEqAst(q"{..$stats}", "{}")
+ assertEqAst(q"{..$stats}", "()")
}
property("consistent variable order") = test {
diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala
index 7c9b5ead20..e96d1186f7 100644
--- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala
@@ -175,4 +175,28 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction
assert(x ≈ q"x")
val q"{ _ * _ }" = q"{ _ * _ }"
}
+
+ property("si-8275 a") = test {
+ val cq"_ => ..$stats" = cq"_ => foo; bar"
+ assert(stats ≈ List(q"foo", q"bar"))
+ }
+
+ property("si-8275 b") = test {
+ val cq"_ => ..$init; $last" = cq"_ => a; b; c"
+ assert(init ≈ List(q"a", q"b"))
+ assert(last ≈ q"c")
+ }
+
+ property("si-8275 c") = test {
+ val cq"_ => ..$stats" = cq"_ =>"
+ assert(stats.isEmpty)
+ assertEqAst(q"{ case _ => ..$stats }", "{ case _ => }")
+ }
+
+ property("can't flatten type into block") = test {
+ assertThrows[IllegalArgumentException] {
+ val tpt = tq"List[Int]"
+ q"..$tpt; ()"
+ }
+ }
}