summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorDenys Shabalin <denys.shabalin@typesafe.com>2014-01-16 11:58:38 +0100
committerDenys Shabalin <denys.shabalin@typesafe.com>2014-01-16 12:45:28 +0100
commit393829489a1e352c2ed659b16b6bea24069f4f9a (patch)
tree8865fa18ef22b959fd5c6b53689afbb0ded84ee3 /src/compiler
parent681308a3aa737be1dae0f702fddadce88c70f90e (diff)
downloadscala-393829489a1e352c2ed659b16b6bea24069f4f9a.tar.gz
scala-393829489a1e352c2ed659b16b6bea24069f4f9a.tar.bz2
scala-393829489a1e352c2ed659b16b6bea24069f4f9a.zip
SI-6844 restrict splicing in parameter position
Previously were a bit too permissive on how splicing in function parameter position worked. This made confusing things like possible: val x = TermName(“x”) q”def foo($x)” Now you can either splice trees in that position (ValDefs) or you have to provide type if you splice a name.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala105
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala16
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala7
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala3
4 files changed, 75 insertions, 56 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index d122a1a207..b13d676c65 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2121,8 +2121,6 @@ self =>
/* -------- PARAMETERS ------------------------------------------- */
- def allowTypelessParams = false
-
/** {{{
* ParamClauses ::= {ParamClause} [[nl] `(' implicit Params `)']
* ParamClause ::= [nl] `(' [Params] `)'
@@ -2137,56 +2135,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
@@ -2195,7 +2143,7 @@ self =>
in.nextToken()
implicitmod = Flags.IMPLICIT
}
- commaSeparated(param())
+ commaSeparated(param(owner, implicitmod, caseParam ))
}
val vds = new ListBuffer[List[ValDef]]
val start = in.offset
@@ -2243,6 +2191,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 6e6b617e5c..7604f779d6 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 =
@@ -193,4 +205,4 @@ trait Parsers { self: Quasiquotes =>
}
object FreshName extends FreshNameExtractor(nme.QUASIQUOTE_PREFIX)
-} \ No newline at end of file
+}
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 87ab52414c..58baad01a1 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
@@ -311,6 +312,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(_)