Skip to content

Commit 3d19187

Browse files
Merge pull request #6198 from dotty-staging/add-quote-patterns
Add quoted patterns
2 parents 578d400 + 1a9ec23 commit 3d19187

File tree

17 files changed

+168
-52
lines changed

17 files changed

+168
-52
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,8 +1013,7 @@ object desugar {
10131013
val arity = ts.length
10141014
assert(arity <= Definitions.MaxTupleArity)
10151015
def tupleTypeRef = defn.TupleType(arity)
1016-
if (arity == 1) ts.head
1017-
else if (arity == 0)
1016+
if (arity == 0)
10181017
if (ctx.mode is Mode.Type) TypeTree(defn.UnitType) else unitLiteral
10191018
else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts)
10201019
else Apply(ref(tupleTypeRef.classSymbol.companionModule.termRef), ts)

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,18 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11781178
}
11791179
}
11801180

1181+
/** An extractor for typed splices */
1182+
object Splice {
1183+
def apply(tree: Tree)(implicit ctx: Context): Tree = {
1184+
val argType = tree.tpe.baseType(defn.QuotedExprClass).argTypesHi.head
1185+
ref(defn.InternalQuoted_exprSplice).appliedToType(argType).appliedTo(tree)
1186+
}
1187+
def unapply(tree: Tree)(implicit ctx: Context): Option[Tree] = tree match {
1188+
case Apply(fn, arg :: Nil) if fn.symbol == defn.InternalQuoted_exprSplice => Some(arg)
1189+
case _ => None
1190+
}
1191+
}
1192+
11811193
/** A key to be used in a context property that tracks enclosing inlined calls */
11821194
private val InlinedCalls = new Property.Key[List[Tree]]
11831195

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
9393
override def isType: Boolean = !isTerm
9494
}
9595
case class Throw(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
96-
case class Quote(t: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
96+
case class Quote(quoted: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
9797
case class Splice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
9898
case class TypSplice(expr: Tree)(implicit @constructorOnly src: SourceFile) extends TypTree
9999
case class DoWhile(body: Tree, cond: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
@@ -492,9 +492,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
492492
case tree: Throw if expr eq tree.expr => tree
493493
case _ => finalize(tree, untpd.Throw(expr)(tree.source))
494494
}
495-
def Quote(tree: Tree)(t: Tree)(implicit ctx: Context): Tree = tree match {
496-
case tree: Quote if t eq tree.t => tree
497-
case _ => finalize(tree, untpd.Quote(t)(tree.source))
495+
def Quote(tree: Tree)(quoted: Tree)(implicit ctx: Context): Tree = tree match {
496+
case tree: Quote if quoted eq tree.quoted => tree
497+
case _ => finalize(tree, untpd.Quote(quoted)(tree.source))
498498
}
499499
def Splice(tree: Tree)(expr: Tree)(implicit ctx: Context): Tree = tree match {
500500
case tree: Splice if expr eq tree.expr => tree

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -705,14 +705,16 @@ class Definitions {
705705
lazy val QuotedExprType: TypeRef = ctx.requiredClassRef("scala.quoted.Expr")
706706
def QuotedExprClass(implicit ctx: Context): ClassSymbol = QuotedExprType.symbol.asClass
707707

708-
lazy val InternalQuotedModule: TermRef = ctx.requiredModuleRef("scala.internal.Quoted")
709-
def InternalQuotedModuleClass: Symbol = InternalQuotedModule.symbol
710-
lazy val InternalQuoted_exprQuoteR: TermRef = InternalQuotedModuleClass.requiredMethodRef("exprQuote".toTermName)
708+
lazy val InternalQuotedModuleRef: TermRef = ctx.requiredModuleRef("scala.internal.Quoted")
709+
def InternalQuotedModule: Symbol = InternalQuotedModuleRef.symbol
710+
lazy val InternalQuoted_exprQuoteR: TermRef = InternalQuotedModule.requiredMethodRef("exprQuote")
711711
def InternalQuoted_exprQuote(implicit ctx: Context): Symbol = InternalQuoted_exprQuoteR.symbol
712-
lazy val InternalQuoted_exprSpliceR: TermRef = InternalQuotedModuleClass.requiredMethodRef("exprSplice".toTermName)
712+
lazy val InternalQuoted_exprSpliceR: TermRef = InternalQuotedModule.requiredMethodRef("exprSplice")
713713
def InternalQuoted_exprSplice(implicit ctx: Context): Symbol = InternalQuoted_exprSpliceR.symbol
714-
lazy val InternalQuoted_typeQuoteR: TermRef = InternalQuotedModuleClass.requiredMethodRef("typeQuote".toTermName)
714+
lazy val InternalQuoted_typeQuoteR: TermRef = InternalQuotedModule.requiredMethodRef("typeQuote")
715715
def InternalQuoted_typeQuote(implicit ctx: Context): Symbol = InternalQuoted_typeQuoteR.symbol
716+
lazy val InternalQuoted_patternHoleR: TermRef = InternalQuotedModule.requiredMethodRef("patternHole")
717+
def InternalQuoted_patternHole(implicit ctx: Context): Symbol = InternalQuoted_patternHoleR.symbol
716718

717719
lazy val QuotedExprsModule: TermSymbol = ctx.requiredModule("scala.quoted.Exprs")
718720
def QuotedExprsClass(implicit ctx: Context): ClassSymbol = QuotedExprsModule.asClass
@@ -723,24 +725,8 @@ class Definitions {
723725
lazy val QuotedType_spliceR: TypeRef = QuotedTypeClass.requiredType(tpnme.splice).typeRef
724726
def QuotedType_splice : Symbol = QuotedType_spliceR.symbol
725727

726-
lazy val QuotedTypeModuleType: TermRef = ctx.requiredModuleRef("scala.quoted.Type")
727-
def QuotedTypeModule(implicit ctx: Context): Symbol = QuotedTypeModuleType.symbol
728-
729-
lazy val QuotedLiftableModule: TermSymbol = ctx.requiredModule("scala.quoted.Liftable")
730-
def QuotedLiftableModuleClass(implicit ctx: Context): ClassSymbol = QuotedLiftableModule.asClass
731-
732-
def QuotedLiftable_BooleanIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("BooleanIsLiftable")
733-
def QuotedLiftable_ByteIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("ByteIsLiftable")
734-
def QuotedLiftable_CharIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("CharIsLiftable")
735-
def QuotedLiftable_ShortIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("ShortIsLiftable")
736-
def QuotedLiftable_IntIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("IntIsLiftable")
737-
def QuotedLiftable_LongIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("LongIsLiftable")
738-
def QuotedLiftable_FloatIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("FloatIsLiftable")
739-
def QuotedLiftable_DoubleIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("DoubleIsLiftable")
740-
def QuotedLiftable_StringIsLiftable: TermRef = QuotedLiftableModule.requiredMethodRef("StringIsLiftable")
741-
742-
lazy val QuotedLiftableType: TypeRef = ctx.requiredClassRef("scala.quoted.Liftable")
743-
def QuotedLiftableClass(implicit ctx: Context): ClassSymbol = QuotedLiftableType.symbol.asClass
728+
lazy val QuotedTypeModuleRef: TermRef = ctx.requiredModuleRef("scala.quoted.Type")
729+
def QuotedTypeModule(implicit ctx: Context): Symbol = QuotedTypeModuleRef.symbol
744730

745731
def Unpickler_unpickleExpr: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleExpr")
746732
def Unpickler_liftedExpr: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.liftedExpr")
@@ -752,6 +738,12 @@ class Definitions {
752738
lazy val TastyReflectionModule: TermSymbol = ctx.requiredModule("scala.tasty.Reflection")
753739
lazy val TastyReflection_macroContext: TermSymbol = TastyReflectionModule.requiredMethod("macroContext")
754740

741+
lazy val QuotedMatcherModuleRef: TermRef = ctx.requiredModuleRef("scala.runtime.quoted.Matcher")
742+
def QuotedMatcherModule(implicit ctx: Context): Symbol = QuotedMatcherModuleRef.symbol
743+
744+
lazy val QuotedMatcher_unapplyR: TermRef = QuotedMatcherModule.requiredMethodRef(nme.unapply)
745+
def QuotedMatcher_unapply(implicit ctx: Context) = QuotedMatcher_unapplyR.symbol
746+
755747
lazy val EqlType: TypeRef = ctx.requiredClassRef("scala.Eql")
756748
def EqlClass(implicit ctx: Context): ClassSymbol = EqlType.symbol.asClass
757749
def EqlModule(implicit ctx: Context): Symbol = EqlClass.companionModule
@@ -1178,7 +1170,9 @@ class Definitions {
11781170
}
11791171

11801172
def tupleType(elems: List[Type]): Type = {
1181-
TupleType(elems.size).appliedTo(elems)
1173+
val arity = elems.length
1174+
if (arity <= MaxTupleArity && TupleType(arity) != null) TupleType(arity).appliedTo(elems)
1175+
else TypeOps.nestedPairs(elems)
11821176
}
11831177

11841178
def isProductSubType(tp: Type)(implicit ctx: Context): Boolean =
@@ -1271,8 +1265,9 @@ class Definitions {
12711265
def adjustForTuple(cls: ClassSymbol, tparams: List[TypeSymbol], parents: List[Type]): List[Type] = {
12721266
def syntheticParent(tparams: List[TypeSymbol]): Type =
12731267
if (tparams.isEmpty) TupleTypeRef
1274-
else (tparams :\ (UnitType: Type)) ((tparam, tail) => PairType.appliedTo(tparam.typeRef, tail))
1275-
if (isTupleClass(cls) || cls == UnitClass) parents :+ syntheticParent(tparams) else parents
1268+
else TypeOps.nestedPairs(tparams.map(_.typeRef))
1269+
if (isTupleClass(cls) || cls == UnitClass) parents :+ syntheticParent(tparams)
1270+
else parents
12761271
}
12771272

12781273
// ----- primitive value class machinery ------------------------------------------

compiler/src/dotty/tools/dotc/core/Mode.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,7 @@ object Mode {
104104

105105
/** Are we trying to find a hidden implicit? */
106106
val FindHiddenImplicits: Mode = newMode(24, "FindHiddenImplicits")
107+
108+
/** Are we in a quote in a pattern? */
109+
val QuotedPattern: Mode = newMode(25, "QuotedPattern")
107110
}

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,4 +567,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
567567

568568
object TypeOps {
569569
@sharable var track: Boolean = false // !!!DEBUG
570+
571+
// TODO: Move other typeops here. It's a bit weird that they are a part of `ctx`
572+
573+
def nestedPairs(ts: List[Type])(implicit ctx: Context): Type =
574+
(ts :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _))
570575
}

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,9 +1478,8 @@ object Parsers {
14781478

14791479
/** SimpleExpr ::= ‘new’ (ConstrApp [TemplateBody] | TemplateBody)
14801480
* | BlockExpr
1481-
* | ‘'’ ‘{’ Block ‘}’
1482-
* | ‘'’ ‘[’ Type ‘]’
14831481
* | ‘$’ ‘{’ Block ‘}’
1482+
* | Quoted
14841483
* | quoteId
14851484
* | SimpleExpr1 [`_']
14861485
* SimpleExpr1 ::= literal
@@ -1490,6 +1489,8 @@ object Parsers {
14901489
* | SimpleExpr `.' id
14911490
* | SimpleExpr (TypeArgs | NamedTypeArgs)
14921491
* | SimpleExpr1 ArgumentExprs
1492+
* Quoted ::= ‘'’ ‘{’ Block ‘}’
1493+
* | ‘'’ ‘[’ Type ‘]’
14931494
*/
14941495
def simpleExpr(): Tree = {
14951496
var canApply = true
@@ -1827,6 +1828,7 @@ object Parsers {
18271828

18281829
/** SimplePattern ::= PatVar
18291830
* | Literal
1831+
* | Quoted
18301832
* | XmlPattern
18311833
* | `(' [Patterns] `)'
18321834
* | SimplePattern1 [TypeArgs] [ArgumentPatterns]
@@ -1853,6 +1855,8 @@ object Parsers {
18531855
} else wildIndent
18541856
case LPAREN =>
18551857
atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt())) }
1858+
case QUOTE =>
1859+
simpleExpr()
18561860
case XMLSTART =>
18571861
xmlLiteralPattern()
18581862
case _ =>

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
179179
val cls = tycon.typeSymbol
180180
if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*"
181181
if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction, cls.name.isErasedFunction)
182-
if (tp.tupleArity >= 2) return toTextTuple(tp.tupleElementTypes)
182+
if (tp.tupleArity >= 2 && !ctx.settings.YprintDebug.value) return toTextTuple(tp.tupleElementTypes)
183183
if (isInfixType(tp)) {
184184
val l :: r :: Nil = args
185185
val opName = tyconName(tycon)

compiler/src/dotty/tools/dotc/transform/TypeUtils.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ object TypeUtils {
4848
else throw new AssertionError("not a tuple")
4949
}
5050

51-
/** The `*:` equivalent of an instantce of a Tuple class */
51+
/** The `*:` equivalent of an instance of a Tuple class */
5252
def toNestedPairs(implicit ctx: Context): Type =
53-
(tupleElementTypes :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _))
53+
TypeOps.nestedPairs(tupleElementTypes)
5454
}
5555
}

compiler/src/dotty/tools/dotc/typer/Deriving.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,14 @@ trait Deriving { this: Typer =>
7878
case _ =>
7979
(sym.termRef, Nil)
8080
}
81-
val elemShape = (elems :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _))
81+
val elemShape = TypeOps.nestedPairs(elems)
8282
defn.ShapeCaseType.appliedTo(constr, elemShape)
8383
}
8484

8585
/** The shape of `cls` if `cls` is sealed */
8686
private def sealedShape: Type = {
8787
val cases = children.map(caseShape).filter(_.exists)
88-
val casesShape = (cases :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _))
88+
val casesShape = TypeOps.nestedPairs(cases)
8989
defn.ShapeCasesType.appliedTo(casesShape)
9090
}
9191

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,7 +1919,7 @@ class Typer extends Namer
19191919
else {
19201920
val elemTpes = (elems, pts).zipped.map((elem, pt) =>
19211921
ctx.typeComparer.widenInferred(elem.tpe, pt))
1922-
val resTpe = (elemTpes :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _))
1922+
val resTpe = TypeOps.nestedPairs(elemTpes)
19231923
app1.cast(resTpe)
19241924
}
19251925
}
@@ -1930,17 +1930,55 @@ class Typer extends Namer
19301930
* while tracking the quotation level in the context.
19311931
*/
19321932
def typedQuote(tree: untpd.Quote, pt: Type)(implicit ctx: Context): Tree = track("typedQuote") {
1933-
tree.t match {
1933+
tree.quoted match {
19341934
case untpd.Splice(innerExpr) =>
19351935
ctx.warning("Canceled splice directly inside a quote. '{ ${ XYZ } } is equivalent to XYZ.", tree.sourcePos)
19361936
typed(innerExpr, pt)
1937-
case t if t.isType =>
1938-
typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuoteR), List(tree.t)), pt)(quoteContext).withSpan(tree.span)
1939-
case t=>
1940-
typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprQuoteR), tree.t), pt)(quoteContext).withSpan(tree.span)
1937+
case quoted if quoted.isType =>
1938+
typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuoteR), quoted :: Nil), pt)(quoteContext).withSpan(tree.span)
1939+
case quoted =>
1940+
if (ctx.mode.is(Mode.Pattern) && level == 0) {
1941+
val exprPt = pt.baseType(defn.QuotedExprClass)
1942+
val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType
1943+
val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode.QuotedPattern))
1944+
val (shape, splices) = splitQuotePattern(quoted1)
1945+
val patType = defn.tupleType(splices.tpes.map(_.widen))
1946+
val splicePat = typed(untpd.Tuple(splices.map(untpd.TypedSplice(_))).withSpan(quoted.span), patType)
1947+
UnApply(
1948+
fun = ref(defn.QuotedMatcher_unapplyR).appliedToType(patType),
1949+
implicits =
1950+
ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) ::
1951+
implicitArgTree(defn.TastyReflectionType, tree.span) :: Nil,
1952+
patterns = splicePat :: Nil,
1953+
proto = pt)
1954+
}
1955+
else
1956+
typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprQuoteR), quoted), pt)(quoteContext).withSpan(tree.span)
1957+
}
1958+
}
1959+
1960+
def splitQuotePattern(quoted: Tree)(implicit ctx: Context): (Tree, List[Tree]) = {
1961+
object splitter extends tpd.TreeMap {
1962+
val patBuf = new mutable.ListBuffer[Tree]
1963+
override def transform(tree: Tree)(implicit ctx: Context) = tree match {
1964+
case Typed(Splice(pat), tpt) =>
1965+
val exprTpt = AppliedTypeTree(TypeTree(defn.QuotedExprType), tpt :: Nil)
1966+
transform(Splice(Typed(pat, exprTpt)))
1967+
case Splice(pat) =>
1968+
try patternHole(tree)
1969+
finally patBuf += pat
1970+
case _ =>
1971+
super.transform(tree)
1972+
}
19411973
}
1974+
val result = splitter.transform(quoted)
1975+
(result, splitter.patBuf.toList)
19421976
}
19431977

1978+
/** A hole the shape pattern of a quoted.Matcher.unapply, representing a splice */
1979+
def patternHole(splice: Tree)(implicit ctx: Context): Tree =
1980+
ref(defn.InternalQuoted_patternHoleR).appliedToType(splice.tpe).withSpan(splice.span)
1981+
19441982
/** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */
19451983
def typedSplice(tree: untpd.Splice, pt: Type)(implicit ctx: Context): Tree = track("typedSplice") {
19461984
checkSpliceOutsideQuote(tree)
@@ -1949,7 +1987,14 @@ class Typer extends Namer
19491987
ctx.warning("Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ.", tree.sourcePos)
19501988
typed(innerExpr, pt)
19511989
case expr =>
1952-
typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprSpliceR), tree.expr), pt)(spliceContext).withSpan(tree.span)
1990+
if (ctx.mode.is(Mode.QuotedPattern) && level == 1) {
1991+
fullyDefinedType(pt, "quoted pattern selector", tree.span)
1992+
val pat = typedPattern(expr, defn.QuotedExprType.appliedTo(pt))(
1993+
spliceContext.retractMode(Mode.QuotedPattern))
1994+
Splice(pat)
1995+
}
1996+
else
1997+
typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprSpliceR), tree.expr), pt)(spliceContext).withSpan(tree.span)
19531998
}
19541999
}
19552000

docs/docs/internals/syntax.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,8 @@ InfixExpr ::= PrefixExpr
209209
PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr PrefixOp(expr, op)
210210
SimpleExpr ::= ‘new’ (ConstrApp [TemplateBody] | TemplateBody) New(constr | templ)
211211
| BlockExpr
212-
| ‘'’ ‘{’ Block ‘}’
213-
| ‘'’ ‘[’ Type ‘]’
214212
| ‘$’ ‘{’ Block ‘}’
213+
| Quoted
215214
| quoteId // only inside splices
216215
| SimpleExpr1 [‘_’] PostfixOp(expr, _)
217216
SimpleExpr1 ::= Literal
@@ -222,6 +221,8 @@ SimpleExpr1 ::= Literal
222221
| SimpleExpr (TypeArgs | NamedTypeArgs) TypeApply(expr, args)
223222
| SimpleExpr1 ArgumentExprs Apply(expr, args)
224223
| XmlExpr
224+
Quoted ::= ‘'’ ‘{’ Block ‘}’
225+
| ‘'’ ‘[’ Type ‘]’
225226
ExprsInParens ::= ExprInParens {‘,’ ExprInParens}
226227
ExprInParens ::= PostfixExpr ‘:’ Type
227228
| Expr
@@ -261,6 +262,7 @@ InfixPattern ::= SimplePattern { id [nl] SimplePattern }
261262
SimplePattern ::= PatVar Ident(wildcard)
262263
| Literal Bind(name, Ident(wildcard))
263264
| ‘(’ [Patterns] ‘)’ Parens(pats) Tuple(pats)
265+
| Quoted
264266
| XmlPattern
265267
| SimplePattern1 [TypeArgs] [ArgumentPatterns]
266268
SimplePattern1 ::= Path

library/src-bootstrapped/scala/internal/Quoted.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ object Quoted {
1616
def typeQuote[T <: AnyKind]: Type[T] =
1717
throw new Error("Internal error: this method call should have been replaced by the compiler")
1818

19+
/** A splice in a quoted pattern is desugared by the compiler into a call to this method */
20+
def patternHole[T]: T =
21+
throw new Error("Internal error: this method call should have been replaced by the compiler")
1922
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package scala.runtime.quoted
2+
3+
import scala.quoted.Expr
4+
import scala.tasty.Reflection
5+
6+
/** THIS IS A PLACEHOLDER
7+
*/
8+
object Matcher {
9+
def unapply[Tup <: Tuple](scrut: Expr[_])(implicit pattern: Expr[_], reflection: Reflection): Option[Tup] = ???
10+
}

library/src/scala/tasty/reflect/Printers.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,10 +1310,17 @@ trait Printers
13101310
printPattern(pattern)
13111311

13121312
case Pattern.Unapply(fun, implicits, patterns) =>
1313-
fun match {
1314-
case Select(extractor, "unapply" | "unapplySeq") => printTree(extractor)
1315-
case TypeApply(Select(extractor, "unapply" | "unapplySeq"), _) => printTree(extractor)
1316-
case _ => throw new MatchError(fun.show)
1313+
val fun2 = fun match {
1314+
case TypeApply(fun2, _) => fun2
1315+
case _ => fun
1316+
}
1317+
fun2 match {
1318+
case Select(extractor, "unapply" | "unapplySeq") =>
1319+
printTree(extractor)
1320+
case Ident("unapply" | "unapplySeq") =>
1321+
this += fun.symbol.owner.fullName.stripSuffix("$")
1322+
case _ =>
1323+
throw new MatchError(fun.show)
13171324
}
13181325
inParens(printPatterns(patterns, ", "))
13191326

tests/neg/quotedPatterns.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
object Test {
2+
3+
val x = '{1 + 2}
4+
5+
def f(x: Int) = x
6+
def g(x: Int, y: Int) = x * y
7+
8+
def test given tasty.Reflection = x match {
9+
case '{ val a = '{ println($y) }; 0 } => ??? // error: Not found: y
10+
case _ =>
11+
}
12+
}

0 commit comments

Comments
 (0)