diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-01-29 01:55:46 -0800 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-01-29 01:55:46 -0800 |
commit | 4506acba688e80a4f778e495a74e7a50f83c4e1b (patch) | |
tree | b05a731dde14ce49f344260ceef2023cd973e646 /src/compiler | |
parent | 057adc70346414c10273f58fcd44114bf0672933 (diff) | |
parent | 8e9862473abd03bded2d3afa60c777099f7872c5 (diff) | |
download | scala-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
Diffstat (limited to 'src/compiler')
4 files changed, 80 insertions, 57 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(_) |