Skip to content

Commit a3c3396

Browse files
Merge pull request #10045 from dotty-staging/quoted-type-pattern
Make type of type hole available in quoted patterns
2 parents 2720af2 + 7bc0173 commit a3c3396

File tree

27 files changed

+101
-97
lines changed

27 files changed

+101
-97
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
160160

161161
/** Is tree a variable pattern? */
162162
def isVarPattern(pat: Tree): Boolean = unsplice(pat) match {
163-
case x: Ident => x.name.isVariableName && !isBackquoted(x)
163+
case x: Ident => x.name.isVarPattern && !isBackquoted(x)
164164
case _ => false
165165
}
166166

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ object NameKinds {
320320
val PatMatStdBinderName: UniqueNameKind = new UniqueNameKind("x")
321321
val PatMatAltsName: UniqueNameKind = new UniqueNameKind("matchAlts")
322322
val PatMatResultName: UniqueNameKind = new UniqueNameKind("matchResult")
323+
val PatMatVarName: UniqueNameKind = new UniqueNameKind("ev$")
323324

324325
val LocalOptInlineLocalObj: UniqueNameKind = new UniqueNameKind("ilo")
325326

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,17 @@ object NameOps {
7979
case name: SimpleName => name.exists(isOperatorPart)
8080
case _ => false
8181

82-
/** Is name a variable name? */
83-
def isVariableName: Boolean = testSimple { n =>
84-
n.length > 0 && {
85-
val first = n.head
86-
(((first.isLower && first.isLetter) || first == '_')
87-
&& (n != false_)
88-
&& (n != true_)
89-
&& (n != null_))
90-
}
91-
}
82+
/** Is name of a variable pattern? */
83+
def isVarPattern: Boolean =
84+
testSimple { n =>
85+
n.length > 0 && {
86+
val first = n.head
87+
(((first.isLower && first.isLetter) || first == '_')
88+
&& (n != false_)
89+
&& (n != true_)
90+
&& (n != null_))
91+
}
92+
} || name.is(PatMatVarName)
9293

9394
def isOpAssignmentName: Boolean = name match {
9495
case raw.NE | raw.LE | raw.GE | EMPTY =>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2594,7 +2594,7 @@ object Parsers {
25942594
val givenMod = atSpan(in.skipToken())(Mod.Given())
25952595
atSpan(in.offset) {
25962596
in.token match {
2597-
case IDENTIFIER | USCORE if in.name.isVariableName =>
2597+
case IDENTIFIER | USCORE if in.name.isVarPattern =>
25982598
val name = in.name
25992599
in.nextToken()
26002600
accept(COLON)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ object PatternMatcher {
194194
case Typed(_, tpt) if tpt.tpe.isRepeatedParam => true
195195
case Bind(nme.WILDCARD, WildcardPattern()) => true // don't skip when binding an interesting symbol!
196196
case t if isWildcardArg(t) => true
197-
case x: Ident => x.name.isVariableName && !isBackquoted(x)
197+
case x: Ident => x.name.isVarPattern && !isBackquoted(x)
198198
case Alternative(ps) => ps.forall(unapply)
199199
case EmptyTree => true
200200
case _ => false

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import dotty.tools.dotc.core.Constants._
99
import dotty.tools.dotc.core.Contexts._
1010
import dotty.tools.dotc.core.Decorators._
1111
import dotty.tools.dotc.core.Flags._
12-
import dotty.tools.dotc.core.NameKinds.UniqueName
12+
import dotty.tools.dotc.core.NameKinds.{UniqueName, PatMatVarName}
1313
import dotty.tools.dotc.core.Names._
1414
import dotty.tools.dotc.core.StagingContext._
1515
import dotty.tools.dotc.core.StdNames._
@@ -156,19 +156,21 @@ trait QuotesAndSplices {
156156
if ctx.mode.is(Mode.QuotedPattern) && level == 1 then
157157
def spliceOwner(ctx: Context): Symbol =
158158
if (ctx.mode.is(Mode.QuotedPattern)) spliceOwner(ctx.outer) else ctx.owner
159-
val name = tree.expr match {
160-
case Ident(name) => ("$" + name).toTypeName
159+
val (name, expr) = tree.expr match {
160+
case Ident(name) =>
161+
val nameOfSyntheticGiven = PatMatVarName.fresh()
162+
(name.toTypeName, untpd.cpy.Ident(tree.expr)(nameOfSyntheticGiven))
161163
case expr =>
162164
report.error("expected a name binding", expr.srcPos)
163-
"$error".toTypeName
165+
("$error".toTypeName, expr)
164166
}
165167

166168
val typeSymInfo = pt match
167169
case pt: TypeBounds => pt
168170
case _ => TypeBounds.empty
169171
val typeSym = newSymbol(spliceOwner(ctx), name, EmptyFlags, typeSymInfo, NoSymbol, tree.expr.span)
170172
typeSym.addAnnotation(Annotation(New(ref(defn.InternalQuotedPatterns_patternTypeAnnot.typeRef)).withSpan(tree.expr.span)))
171-
val pat = typedPattern(tree.expr, defn.QuotedTypeClass.typeRef.appliedTo(typeSym.typeRef))(
173+
val pat = typedPattern(expr, defn.QuotedTypeClass.typeRef.appliedTo(typeSym.typeRef))(
172174
using spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
173175
pat.select(tpnme.spliceType)
174176
else
@@ -214,7 +216,7 @@ trait QuotesAndSplices {
214216
def getBinding(sym: Symbol): Bind =
215217
typeBindings.getOrElseUpdate(sym, {
216218
val bindingBounds = sym.info
217-
val bsym = newPatternBoundSymbol(sym.name.toTypeName, bindingBounds, quoted.span)
219+
val bsym = newPatternBoundSymbol(sym.name.toString.stripPrefix("$").toTypeName, bindingBounds, quoted.span)
218220
Bind(bsym, untpd.Ident(nme.WILDCARD).withType(bindingBounds)).withSpan(quoted.span)
219221
})
220222

@@ -263,13 +265,14 @@ trait QuotesAndSplices {
263265
val sym = tree.tpe.dealias.typeSymbol
264266
if sym.exists then
265267
val tdef = TypeDef(sym.asType).withSpan(sym.span)
266-
freshTypeBindingsBuff += transformTypeBindingTypeDef(tdef, freshTypePatBuf)
268+
val nameOfSyntheticGiven = pat.symbol.name.toTermName
269+
freshTypeBindingsBuff += transformTypeBindingTypeDef(nameOfSyntheticGiven, tdef, freshTypePatBuf)
267270
TypeTree(tree.tpe.dealias).withSpan(tree.span)
268271
else
269272
tree
270273
case tdef: TypeDef =>
271274
if tdef.symbol.hasAnnotation(defn.InternalQuotedPatterns_patternTypeAnnot) then
272-
transformTypeBindingTypeDef(tdef, typePatBuf)
275+
transformTypeBindingTypeDef(PatMatVarName.fresh(), tdef, typePatBuf)
273276
else if tdef.symbol.isClass then
274277
val kind = if tdef.symbol.is(Module) then "objects" else "classes"
275278
report.error("Implementation restriction: cannot match " + kind, tree.srcPos)
@@ -305,13 +308,12 @@ trait QuotesAndSplices {
305308
super.transform(tree)
306309
}
307310

308-
private def transformTypeBindingTypeDef(tdef: TypeDef, buff: mutable.Builder[Tree, List[Tree]])(using Context): Tree = {
311+
private def transformTypeBindingTypeDef(nameOfSyntheticGiven: TermName, tdef: TypeDef, buff: mutable.Builder[Tree, List[Tree]])(using Context): Tree = {
309312
if (variance == -1)
310313
tdef.symbol.addAnnotation(Annotation(New(ref(defn.InternalQuotedPatterns_fromAboveAnnot.typeRef)).withSpan(tdef.span)))
311314
val bindingType = getBinding(tdef.symbol).symbol.typeRef
312315
val bindingTypeTpe = AppliedType(defn.QuotedTypeClass.typeRef, bindingType :: Nil)
313-
val bindName = tdef.name.toString.stripPrefix("$").toTermName
314-
val sym = newPatternBoundSymbol(bindName, bindingTypeTpe, tdef.span, flags = ImplicitTerm)(using ctx0)
316+
val sym = newPatternBoundSymbol(nameOfSyntheticGiven, bindingTypeTpe, tdef.span, flags = ImplicitTerm)(using ctx0)
315317
buff += Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingTypeTpe)).withSpan(tdef.span)
316318
super.transform(tdef)
317319
}

tests/neg-macros/quotedPatterns-5.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import scala.quoted._
22
object Test {
3-
def test(x: quoted.Expr[Int])(using QuoteContext) = x match {
4-
case '{ type $t; poly[$t]($x); 4 } => ??? // error: duplicate pattern variable: $t
5-
case '{ type `$t`; poly[`$t`]($x); 4 } =>
6-
val tt: quoted.Type[_] = t // error
7-
???
3+
def test(x: quoted.Expr[Int])(using QuoteContext): Unit = x match {
4+
case '{ type $T; 4 } => Type[T]
5+
case '{ type $T; poly[$T]($x); 4 } => // error: duplicate pattern variable: T
6+
case '{ type `$T`; poly[`$T`]($x); 4 } =>
7+
Type[T] // error
88
case _ =>
99
}
1010

0 commit comments

Comments
 (0)