Skip to content

Commit 12adbea

Browse files
Merge pull request #6212 from nicolasstucki/add-quote-pattern-bindings
Add quote pattern bindings
2 parents 1c3b45a + cf5f6f1 commit 12adbea

File tree

22 files changed

+546
-41
lines changed

22 files changed

+546
-41
lines changed

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

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ object desugar {
139139
* def x: Int = expr
140140
* def x_=($1: <TypeTree()>): Unit = ()
141141
*/
142-
def valDef(vdef: ValDef)(implicit ctx: Context): Tree = {
143-
val ValDef(name, tpt, rhs) = vdef
142+
def valDef(vdef0: ValDef)(implicit ctx: Context): Tree = {
143+
val vdef @ ValDef(name, tpt, rhs) = transformQuotedPatternName(vdef0)
144144
val mods = vdef.mods
145145
val setterNeeded =
146146
(mods is Mutable) && ctx.owner.isClass && (!(mods is PrivateLocal) || (ctx.owner is Trait))
@@ -197,8 +197,8 @@ object desugar {
197197
* ==>
198198
* inline def f(x: Boolean): Any = (if (x) 1 else ""): Any
199199
*/
200-
private def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
201-
val DefDef(_, tparams, vparamss, tpt, rhs) = meth
200+
private def defDef(meth0: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
201+
val meth @ DefDef(_, tparams, vparamss, tpt, rhs) = transformQuotedPatternName(meth0)
202202
val methName = normalizeName(meth, tpt).asTermName
203203
val mods = meth.mods
204204
val epbuf = new ListBuffer[ValDef]
@@ -272,6 +272,32 @@ object desugar {
272272
}
273273
}
274274

275+
/** Transforms a definition with a name starting with a `$` in a quoted pattern into a `quoted.binding.Binding` splice.
276+
*
277+
* The desugaring consists in renaming the the definition and adding the `@patternBindHole` annotation. This
278+
* annotation is used during typing to perform the full transformation.
279+
*
280+
* A definition
281+
* ```scala
282+
* case '{ def $a(...) = ... a() ...; ... a() ... }
283+
* ```
284+
* into
285+
* ```scala
286+
* case '{ @patternBindHole def a(...) = ... a() ...; ... a() ... }
287+
* ```
288+
*/
289+
def transformQuotedPatternName(tree: ValOrDefDef)(implicit ctx: Context): ValOrDefDef = {
290+
if (ctx.mode.is(Mode.QuotedPattern) && !tree.isBackquoted && tree.name != nme.ANON_FUN && tree.name.startsWith("$")) {
291+
val name = tree.name.toString.substring(1).toTermName
292+
val newTree: ValOrDefDef = tree match {
293+
case tree: ValDef => cpy.ValDef(tree)(name)
294+
case tree: DefDef => cpy.DefDef(tree)(name)
295+
}
296+
val mods = tree.mods.withAddedAnnotation(New(ref(defn.InternalQuoted_patternBindHoleAnnot.typeRef)).withSpan(tree.span))
297+
newTree.withMods(mods)
298+
} else tree
299+
}
300+
275301
// Add all evidence parameters in `params` as implicit parameters to `meth` */
276302
private def addEvidenceParams(meth: DefDef, params: List[ValDef])(implicit ctx: Context): DefDef =
277303
params match {

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,14 @@ object Trees {
357357

358358
/** A ValDef or DefDef tree */
359359
abstract class ValOrDefDef[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends MemberDef[T] with WithLazyField[Tree[T]] {
360+
type ThisTree[-T >: Untyped] <: ValOrDefDef[T]
360361
def name: TermName
361362
def tpt: Tree[T]
362363
def unforcedRhs: LazyTree = unforced
363364
def rhs(implicit ctx: Context): Tree[T] = forceIfLazy
365+
366+
/** Is this a `BackquotedValDef` or `BackquotedDefDef` ? */
367+
def isBackquoted: Boolean = false
364368
}
365369

366370
// ----------- Tree case classes ------------------------------------
@@ -706,6 +710,12 @@ object Trees {
706710
protected def force(x: AnyRef): Unit = preRhs = x
707711
}
708712

713+
class BackquotedValDef[-T >: Untyped] private[ast] (name: TermName, tpt: Tree[T], preRhs: LazyTree)(implicit @constructorOnly src: SourceFile)
714+
extends ValDef[T](name, tpt, preRhs) {
715+
override def isBackquoted: Boolean = true
716+
override def productPrefix: String = "BackquotedValDef"
717+
}
718+
709719
/** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */
710720
case class DefDef[-T >: Untyped] private[ast] (name: TermName, tparams: List[TypeDef[T]],
711721
vparamss: List[List[ValDef[T]]], tpt: Tree[T], private var preRhs: LazyTree)(implicit @constructorOnly src: SourceFile)
@@ -716,6 +726,13 @@ object Trees {
716726
protected def force(x: AnyRef): Unit = preRhs = x
717727
}
718728

729+
class BackquotedDefDef[-T >: Untyped] private[ast] (name: TermName, tparams: List[TypeDef[T]],
730+
vparamss: List[List[ValDef[T]]], tpt: Tree[T], preRhs: LazyTree)(implicit @constructorOnly src: SourceFile)
731+
extends DefDef[T](name, tparams, vparamss, tpt, preRhs) {
732+
override def isBackquoted: Boolean = true
733+
override def productPrefix: String = "BackquotedDefDef"
734+
}
735+
719736
/** mods class name template or
720737
* mods trait name template or
721738
* mods type name = rhs or
@@ -932,7 +949,9 @@ object Trees {
932949
type Alternative = Trees.Alternative[T]
933950
type UnApply = Trees.UnApply[T]
934951
type ValDef = Trees.ValDef[T]
952+
type BackquotedValDef = Trees.BackquotedValDef[T]
935953
type DefDef = Trees.DefDef[T]
954+
type BackquotedDefDef = Trees.BackquotedDefDef[T]
936955
type TypeDef = Trees.TypeDef[T]
937956
type Template = Trees.Template[T]
938957
type Import = Trees.Import[T]
@@ -1125,10 +1144,16 @@ object Trees {
11251144
case _ => finalize(tree, untpd.UnApply(fun, implicits, patterns)(sourceFile(tree)))
11261145
}
11271146
def ValDef(tree: Tree)(name: TermName, tpt: Tree, rhs: LazyTree)(implicit ctx: Context): ValDef = tree match {
1147+
case tree: BackquotedValDef =>
1148+
if ((name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs)) tree
1149+
else finalize(tree, untpd.BackquotedValDef(name, tpt, rhs)(sourceFile(tree)))
11281150
case tree: ValDef if (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree
11291151
case _ => finalize(tree, untpd.ValDef(name, tpt, rhs)(sourceFile(tree)))
11301152
}
11311153
def DefDef(tree: Tree)(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit ctx: Context): DefDef = tree match {
1154+
case tree: BackquotedDefDef =>
1155+
if ((name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs)) tree
1156+
else finalize(tree, untpd.BackquotedDefDef(name, tparams, vparamss, tpt, rhs)(sourceFile(tree)))
11321157
case tree: DefDef if (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree
11331158
case _ => finalize(tree, untpd.DefDef(name, tparams, vparamss, tpt, rhs)(sourceFile(tree)))
11341159
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
321321
def Alternative(trees: List[Tree])(implicit src: SourceFile): Alternative = new Alternative(trees)
322322
def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit src: SourceFile): UnApply = new UnApply(fun, implicits, patterns)
323323
def ValDef(name: TermName, tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): ValDef = new ValDef(name, tpt, rhs)
324+
def BackquotedValDef(name: TermName, tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): ValDef = new BackquotedValDef(name, tpt, rhs)
324325
def DefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): DefDef = new DefDef(name, tparams, vparamss, tpt, rhs)
326+
def BackquotedDefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): DefDef = new BackquotedDefDef(name, tparams, vparamss, tpt, rhs)
325327
def TypeDef(name: TypeName, rhs: Tree)(implicit src: SourceFile): TypeDef = new TypeDef(name, rhs)
326328
def Template(constr: DefDef, parents: List[Tree], derived: List[Tree], self: ValDef, body: LazyTreeList)(implicit src: SourceFile): Template =
327329
if (derived.isEmpty) new Template(constr, parents, self, body)
@@ -406,8 +408,12 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
406408
def makeAndType(left: Tree, right: Tree)(implicit ctx: Context): AppliedTypeTree =
407409
AppliedTypeTree(ref(defn.andType.typeRef), left :: right :: Nil)
408410

409-
def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = EmptyModifiers)(implicit ctx: Context): ValDef =
410-
ValDef(pname, tpe, EmptyTree).withMods(mods | Param)
411+
def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = EmptyModifiers, isBackquoted: Boolean = false)(implicit ctx: Context): ValDef = {
412+
val vdef =
413+
if (isBackquoted) BackquotedValDef(pname, tpe, EmptyTree)
414+
else ValDef(pname, tpe, EmptyTree)
415+
vdef.withMods(mods | Param)
416+
}
411417

412418
def makeSyntheticParameter(n: Int = 1, tpt: Tree = null, flags: FlagSet = EmptyFlags)(implicit ctx: Context): ValDef =
413419
ValDef(nme.syntheticParamName(n), if (tpt == null) TypeTree() else tpt, EmptyTree)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ class Definitions {
722722
def InternalQuoted_typeQuote(implicit ctx: Context): Symbol = InternalQuoted_typeQuoteR.symbol
723723
lazy val InternalQuoted_patternHoleR: TermRef = InternalQuotedModule.requiredMethodRef("patternHole")
724724
def InternalQuoted_patternHole(implicit ctx: Context): Symbol = InternalQuoted_patternHoleR.symbol
725+
lazy val InternalQuoted_patternBindHoleAnnot: ClassSymbol = InternalQuotedModule.requiredClass("patternBindHole")
725726

726727
lazy val InternalQuotedMatcherModuleRef: TermRef = ctx.requiredModuleRef("scala.internal.quoted.Matcher")
727728
def InternalQuotedMatcherModule(implicit ctx: Context): Symbol = InternalQuotedMatcherModuleRef.symbol
@@ -741,6 +742,9 @@ class Definitions {
741742
lazy val QuotedTypeModuleRef: TermRef = ctx.requiredModuleRef("scala.quoted.Type")
742743
def QuotedTypeModule(implicit ctx: Context): Symbol = QuotedTypeModuleRef.symbol
743744

745+
lazy val QuotedMatchingBindingType: TypeRef = ctx.requiredClassRef("scala.quoted.matching.Bind")
746+
def QuotedMatchingBindingClass(implicit ctx: Context): ClassSymbol = QuotedMatchingBindingType.symbol.asClass
747+
744748
def Unpickler_unpickleExpr: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleExpr")
745749
def Unpickler_liftedExpr: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.liftedExpr")
746750
def Unpickler_unpickleType: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType")

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

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,12 @@ object Parsers {
406406
/** Convert tree to formal parameter
407407
*/
408408
def convertToParam(tree: Tree, expected: String = "formal parameter"): ValDef = tree match {
409-
case Ident(name) =>
410-
makeParameter(name.asTermName, TypeTree()).withSpan(tree.span)
411-
case Typed(Ident(name), tpt) =>
412-
makeParameter(name.asTermName, tpt).withSpan(tree.span)
409+
case id @ Ident(name) =>
410+
makeParameter(name.asTermName, TypeTree(), isBackquoted = id.isBackquoted).withSpan(tree.span)
411+
case Typed(id @ Ident(name), tpt) =>
412+
makeParameter(name.asTermName, tpt, isBackquoted = id.isBackquoted).withSpan(tree.span)
413+
case Typed(Splice(Ident(name)), tpt) =>
414+
makeParameter(("$" + name).toTermName, tpt).withSpan(tree.span)
413415
case _ =>
414416
syntaxError(s"not a legal $expected", tree.span)
415417
makeParameter(nme.ERROR, tree)
@@ -2370,7 +2372,9 @@ object Parsers {
23702372
}
23712373
} else EmptyTree
23722374
lhs match {
2373-
case (id @ Ident(name: TermName)) :: Nil => {
2375+
case (id: BackquotedIdent) :: Nil if id.name.isTermName =>
2376+
finalizeDef(BackquotedValDef(id.name.asTermName, tpt, rhs), mods, start)
2377+
case Ident(name: TermName) :: Nil => {
23742378
finalizeDef(ValDef(name, tpt, rhs), mods, start)
23752379
} case _ =>
23762380
PatDef(mods, lhs, tpt, rhs)
@@ -2414,10 +2418,10 @@ object Parsers {
24142418
else
24152419
(Nil, Method)
24162420
val mods1 = addFlag(mods, flags)
2417-
val name = ident()
2421+
val ident = termIdent()
24182422
val tparams = typeParamClauseOpt(ParamOwner.Def)
24192423
val vparamss = paramClauses() match {
2420-
case rparams :: rparamss if leadingParamss.nonEmpty && !isLeftAssoc(name) =>
2424+
case rparams :: rparamss if leadingParamss.nonEmpty && !isLeftAssoc(ident.name) =>
24212425
rparams :: leadingParamss ::: rparamss
24222426
case rparamss =>
24232427
leadingParamss ::: rparamss
@@ -2447,7 +2451,9 @@ object Parsers {
24472451
accept(EQUALS)
24482452
expr()
24492453
}
2450-
finalizeDef(DefDef(name, tparams, vparamss, tpt, rhs), mods1, start)
2454+
2455+
if (ident.isBackquoted) finalizeDef(BackquotedDefDef(ident.name.asTermName, tparams, vparamss, tpt, rhs), mods1, start)
2456+
else finalizeDef(DefDef(ident.name.asTermName, tparams, vparamss, tpt, rhs), mods1, start)
24512457
}
24522458
}
24532459

compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,6 +1810,7 @@ class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util.
18101810
def Definitions_TupleClass(arity: Int): Symbol = defn.TupleType(arity).classSymbol.asClass
18111811

18121812
def Definitions_InternalQuoted_patternHole: Symbol = defn.InternalQuoted_patternHole
1813+
def Definitions_InternalQuoted_patternBindHoleAnnot: Symbol = defn.InternalQuoted_patternBindHoleAnnot
18131814

18141815
// Types
18151816

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,7 @@ class Typer extends Namer
19591959
}
19601960

19611961
def splitQuotePattern(quoted: Tree)(implicit ctx: Context): (Tree, List[Tree]) = {
1962+
val ctx0 = ctx
19621963
object splitter extends tpd.TreeMap {
19631964
val patBuf = new mutable.ListBuffer[Tree]
19641965
override def transform(tree: Tree)(implicit ctx: Context) = tree match {
@@ -1973,6 +1974,22 @@ class Typer extends Namer
19731974
val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
19741975
patBuf += pat1
19751976
}
1977+
case ddef: ValOrDefDef =>
1978+
if (ddef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot)) {
1979+
val bindingType = ddef.symbol.info match {
1980+
case t: ExprType => t.resType
1981+
case t: MethodType => t.toFunctionType()
1982+
case t: PolyType =>
1983+
HKTypeLambda(t.paramNames)(
1984+
x => t.paramInfos.mapConserve(_.subst(t, x).asInstanceOf[TypeBounds]),
1985+
x => t.resType.subst(t, x).toFunctionType())
1986+
case t => t
1987+
}
1988+
val bindingExprTpe = AppliedType(defn.QuotedMatchingBindingType, bindingType :: Nil)
1989+
val sym = ctx0.newPatternBoundSymbol(ddef.name, bindingExprTpe, ddef.span)
1990+
patBuf += Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingExprTpe)).withSpan(ddef.span)
1991+
}
1992+
super.transform(tree)
19761993
case _ =>
19771994
super.transform(tree)
19781995
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package scala.internal
22

3+
import scala.annotation.Annotation
34
import scala.quoted._
45

56
object Quoted {
@@ -19,4 +20,8 @@ object Quoted {
1920
/** A splice in a quoted pattern is desugared by the compiler into a call to this method */
2021
def patternHole[T]: T =
2122
throw new Error("Internal error: this method call should have been replaced by the compiler")
23+
24+
/** A splice of a name in a quoted pattern is desugared by wrapping getting this annotation */
25+
class patternBindHole extends Annotation
26+
2227
}

library/src-bootstrapped/scala/internal/quoted/Matcher.scala

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package scala.internal.quoted
33
import scala.annotation.internal.sharable
44

55
import scala.quoted._
6+
import scala.quoted.matching.Bind
67
import scala.tasty._
78

89
object Matcher {
@@ -30,7 +31,8 @@ object Matcher {
3031
* @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Expr[Ti]``
3132
*/
3233
def unapply[Tup <: Tuple](scrutineeExpr: Expr[_])(implicit patternExpr: Expr[_], reflection: Reflection): Option[Tup] = {
33-
import reflection._
34+
import reflection.{Bind => BindPattern, _}
35+
3436
// TODO improve performance
3537

3638
/** Check that the trees match and return the contents from the pattern holes.
@@ -51,6 +53,18 @@ object Matcher {
5153
sFlags.is(Lazy) == pFlags.is(Lazy) && sFlags.is(Mutable) == pFlags.is(Mutable)
5254
}
5355

56+
def bindingMatch(sym: Symbol) =
57+
Some(Tuple1(new Bind(sym.name, sym)))
58+
59+
def hasBindTypeAnnotation(tpt: TypeTree): Boolean = tpt match {
60+
case Annotated(tpt2, Apply(Select(New(TypeIdent("patternBindHole")), "<init>"), Nil)) => true
61+
case Annotated(tpt2, _) => hasBindTypeAnnotation(tpt2)
62+
case _ => false
63+
}
64+
65+
def hasBindAnnotation(sym: Symbol) =
66+
sym.annots.exists { case Apply(Select(New(TypeIdent("patternBindHole")),"<init>"),List()) => true; case _ => true }
67+
5468
def treesMatch(scrutinees: List[Tree], patterns: List[Tree]): Option[Tuple] =
5569
if (scrutinees.size != patterns.size) None
5670
else foldMatchings(scrutinees.zip(patterns).map(treeMatches): _*)
@@ -142,24 +156,30 @@ object Matcher {
142156
foldMatchings(treeMatches(tycon1, tycon2), treesMatch(args1, args2))
143157

144158
case (ValDef(_, tpt1, rhs1), ValDef(_, tpt2, rhs2)) if checkValFlags() =>
159+
val bindMatch =
160+
if (hasBindAnnotation(pattern.symbol) || hasBindTypeAnnotation(tpt2)) bindingMatch(scrutinee.symbol)
161+
else Some(())
145162
val returnTptMatch = treeMatches(tpt1, tpt2)
146163
val rhsEnv = env + (scrutinee.symbol -> pattern.symbol)
147164
val rhsMatchings = treeOptMatches(rhs1, rhs2)(rhsEnv)
148-
foldMatchings(returnTptMatch, rhsMatchings)
165+
foldMatchings(bindMatch, returnTptMatch, rhsMatchings)
149166

150167
case (DefDef(_, typeParams1, paramss1, tpt1, Some(rhs1)), DefDef(_, typeParams2, paramss2, tpt2, Some(rhs2))) =>
151168
val typeParmasMatch = treesMatch(typeParams1, typeParams2)
152169
val paramssMatch =
153170
if (paramss1.size != paramss2.size) None
154171
else foldMatchings(paramss1.zip(paramss2).map { (params1, params2) => treesMatch(params1, params2) }: _*)
172+
val bindMatch =
173+
if (hasBindAnnotation(pattern.symbol)) bindingMatch(scrutinee.symbol)
174+
else Some(())
155175
val tptMatch = treeMatches(tpt1, tpt2)
156176
val rhsEnv =
157177
env + (scrutinee.symbol -> pattern.symbol) ++
158-
typeParams1.zip(typeParams2).map((tparam1, tparam2) => tparam1.symbol -> tparam2.symbol) ++
159-
paramss1.flatten.zip(paramss2.flatten).map((param1, param2) => param1.symbol -> param2.symbol)
178+
typeParams1.zip(typeParams2).map((tparam1, tparam2) => tparam1.symbol -> tparam2.symbol) ++
179+
paramss1.flatten.zip(paramss2.flatten).map((param1, param2) => param1.symbol -> param2.symbol)
160180
val rhsMatch = treeMatches(rhs1, rhs2)(rhsEnv)
161181

162-
foldMatchings(typeParmasMatch, paramssMatch, tptMatch, rhsMatch)
182+
foldMatchings(bindMatch, typeParmasMatch, paramssMatch, tptMatch, rhsMatch)
163183

164184
case (Lambda(_, tpt1), Lambda(_, tpt2)) =>
165185
// TODO match tpt1 with tpt2?
@@ -180,6 +200,10 @@ object Matcher {
180200
val finalizerMatch = treeOptMatches(finalizer1, finalizer2)
181201
foldMatchings(bodyMacth, casesMatch, finalizerMatch)
182202

203+
// Ignore type annotations
204+
case (Annotated(tpt, _), _) => treeMatches(tpt, pattern)
205+
case (_, Annotated(tpt, _)) => treeMatches(scrutinee, tpt)
206+
183207
// No Match
184208
case _ =>
185209
if (debug)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package scala.quoted
2+
package matching
3+
4+
import scala.tasty.Reflection // TODO do not depend on reflection directly
5+
6+
/** Bind of an Expr[T] used to know if some Expr[T] is a reference to the binding
7+
*
8+
* @param name string name of this binding
9+
* @param id unique id used for equality
10+
*/
11+
class Bind[T <: AnyKind] private[scala](val name: String, private[Bind] val id: Object) { self =>
12+
13+
override def equals(obj: Any): Boolean = obj match {
14+
case obj: Bind[_] => obj.id == id
15+
case _ => false
16+
}
17+
18+
override def hashCode(): Int = id.hashCode()
19+
20+
}
21+
22+
object Bind {
23+
24+
def unapply[T](expr: Expr[T])(implicit reflect: Reflection): Option[Bind[T]] = {
25+
import reflect.{Bind => BindPattern, _}
26+
expr.unseal match {
27+
case IsIdent(ref) =>
28+
val sym = ref.symbol
29+
Some(new Bind[T](sym.name, sym))
30+
case _ => None
31+
}
32+
}
33+
34+
}

0 commit comments

Comments
 (0)