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

0 commit comments

Comments
 (0)