Skip to content

Remove quoted name splices #8693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 2 additions & 22 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ object desugar {
* - all package object members
*/
def valDef(vdef0: ValDef)(implicit ctx: Context): Tree = {
val vdef @ ValDef(name, tpt, rhs) = transformQuotedPatternName(vdef0)
val vdef @ ValDef(name, tpt, rhs) = vdef0
val mods = vdef.mods
val setterNeeded =
mods.is(Mutable)
Expand Down Expand Up @@ -204,7 +204,7 @@ object desugar {
* def f$default$2[T](x: Int) = x + "m"
*/
private def defDef(meth0: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
val meth @ DefDef(_, tparams, vparamss, tpt, rhs) = transformQuotedPatternName(meth0)
val meth @ DefDef(_, tparams, vparamss, tpt, rhs) = meth0
val methName = normalizeName(meth, tpt).asTermName
val mods = meth.mods
val epbuf = ListBuffer[ValDef]()
Expand Down Expand Up @@ -279,26 +279,6 @@ object desugar {
}
}

/** Transforms a definition with a name starting with a `$` in a quoted pattern into a `quoted.binding.Binding` splice.
*
* The desugaring consists in adding the `@patternBindHole` annotation. This annotation is used during typing to perform the full transformation.
*
* A definition
* ```scala
* case '{ def $a(...) = ...; ... `$a`() ... } => a
* ```
* into
* ```scala
* case '{ @patternBindHole def `$a`(...) = ...; ... `$a`() ... } => a
* ```
*/
def transformQuotedPatternName(tree: ValOrDefDef)(implicit ctx: Context): ValOrDefDef =
if (ctx.mode.is(Mode.QuotedPattern) && !isBackquoted(tree) && tree.name != nme.ANON_FUN && tree.name.startsWith("$")) {
val mods = tree.mods.withAddedAnnotation(New(ref(defn.InternalQuoted_patternBindHoleAnnot.typeRef)).withSpan(tree.span))
tree.withMods(mods)
}
else tree

/** Add an explicit ascription to the `expectedTpt` to every tail splice.
*
* - `'{ x }` -> `'{ x }`
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,6 @@ class Definitions {
@tu lazy val InternalQuoted_exprNestedSplice : Symbol = InternalQuotedModule.requiredMethod("exprNestedSplice")
@tu lazy val InternalQuoted_typeQuote : Symbol = InternalQuotedModule.requiredMethod("typeQuote")
@tu lazy val InternalQuoted_patternHole: Symbol = InternalQuotedModule.requiredMethod("patternHole")
@tu lazy val InternalQuoted_patternBindHoleAnnot: ClassSymbol = InternalQuotedModule.requiredClass("patternBindHole")
@tu lazy val InternalQuoted_patternTypeAnnot: ClassSymbol = InternalQuotedModule.requiredClass("patternType")
@tu lazy val InternalQuoted_QuoteTypeTagAnnot: ClassSymbol = InternalQuotedModule.requiredClass("quoteTypeTag")
@tu lazy val InternalQuoted_fromAboveAnnot: ClassSymbol = InternalQuotedModule.requiredClass("fromAbove")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1963,7 +1963,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
def Definitions_isTupleClass(sym: Symbol): Boolean = defn.isTupleClass(sym)

def Definitions_InternalQuoted_patternHole: Symbol = defn.InternalQuoted_patternHole
def Definitions_InternalQuoted_patternBindHoleAnnot: Symbol = defn.InternalQuoted_patternBindHoleAnnot
def Definitions_InternalQuoted_patternTypeAnnot: Symbol = defn.InternalQuoted_patternTypeAnnot
def Definitions_InternalQuoted_fromAboveAnnot: Symbol = defn.InternalQuoted_fromAboveAnnot

Expand Down
17 changes: 0 additions & 17 deletions compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
Original file line number Diff line number Diff line change
Expand Up @@ -219,23 +219,6 @@ trait QuotesAndSplices {
TypeTree(tree.tpe.dealias).withSpan(tree.span)
else
tree
case ddef: ValOrDefDef =>
if (ddef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot)) {
val bindingType = ddef.symbol.info match {
case t: ExprType => t.resType
case t: MethodType => t.toFunctionType()
case t: PolyType =>
HKTypeLambda(t.paramNames)(
x => t.paramInfos.mapConserve(_.subst(t, x).asInstanceOf[TypeBounds]),
x => t.resType.subst(t, x).toFunctionType())
case t => t
}
assert(ddef.name.startsWith("$"))
val bindName = ddef.name.toString.stripPrefix("$").toTermName
val sym = ctx0.newPatternBoundSymbol(bindName, defn.StringType, ddef.span)
patBuf += Bind(sym, untpd.Ident(nme.WILDCARD).withType(defn.StringType)).withSpan(ddef.span)
}
super.transform(tree)
case tdef: TypeDef if tdef.symbol.hasAnnotation(defn.InternalQuoted_patternTypeAnnot) =>
transformTypeBindingTypeDef(tdef, typePatBuf)
case tree @ AppliedTypeTree(tpt, args) =>
Expand Down
1 change: 1 addition & 0 deletions library/src/scala/internal/quoted/CompileTime.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ object CompileTime {
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternHole`")
def patternHole[T]: T = ???

// TODO remove
/** A splice of a name in a quoted pattern is desugared by wrapping getting this annotation */
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.patternBindHole`")
class patternBindHole extends Annotation
Expand Down
32 changes: 5 additions & 27 deletions library/src/scala/internal/quoted/Matcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,27 +69,15 @@ private[quoted] object Matcher {
}
}

private def hasBindTypeAnnotation(tpt: TypeTree): Boolean = tpt match {
case Annotated(tpt2, annot) => isBindAnnotation(annot) || hasBindTypeAnnotation(tpt2)
case _ => false
}

private def hasPatternTypeAnnotation(sym: Symbol) = sym.annots.exists(isPatternTypeAnnotation)

private def hasBindAnnotation(sym: Symbol) = sym.annots.exists(isBindAnnotation)

private def hasFromAboveAnnotation(sym: Symbol) = sym.annots.exists(isFromAboveAnnotation)

private def isPatternTypeAnnotation(tree: Tree): Boolean = tree match {
case New(tpt) => tpt.symbol == internal.Definitions_InternalQuoted_patternTypeAnnot
case annot => annot.symbol.owner == internal.Definitions_InternalQuoted_patternTypeAnnot
}

private def isBindAnnotation(tree: Tree): Boolean = tree match {
case New(tpt) => tpt.symbol == internal.Definitions_InternalQuoted_patternBindHoleAnnot
case annot => annot.symbol.owner == internal.Definitions_InternalQuoted_patternBindHoleAnnot
}

private def isFromAboveAnnotation(tree: Tree): Boolean = tree match {
case New(tpt) => tpt.symbol == internal.Definitions_InternalQuoted_fromAboveAnnot
case annot => annot.symbol.owner == internal.Definitions_InternalQuoted_fromAboveAnnot
Expand Down Expand Up @@ -139,9 +127,6 @@ private[quoted] object Matcher {
sFlags.is(Lazy) == pFlags.is(Lazy) && sFlags.is(Mutable) == pFlags.is(Mutable)
}

def bindingMatch(sym: Symbol) =
matched(sym.name)

(scrutinee, pattern) match {

// Match a scala.internal.Quoted.patternHole typed as a repeated argument and return the scrutinee tree
Expand Down Expand Up @@ -254,28 +239,21 @@ private[quoted] object Matcher {
tycon1 =?= tycon2 && args1 =?= args2

case (ValDef(_, tpt1, rhs1), ValDef(_, tpt2, rhs2)) if checkValFlags() =>
val bindMatch =
if (hasBindAnnotation(pattern.symbol) || hasBindTypeAnnotation(tpt2)) bindingMatch(scrutinee.symbol)
else matched
def rhsEnv = summon[Env] + (scrutinee.symbol -> pattern.symbol)
bindMatch && tpt1 =?= tpt2 && treeOptMatches(rhs1, rhs2)(using summon[Context], rhsEnv)
tpt1 =?= tpt2 && treeOptMatches(rhs1, rhs2)(using summon[Context], rhsEnv)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern matching on definitions up to alpha-conversion 👍


case (DefDef(_, typeParams1, paramss1, tpt1, Some(rhs1)), DefDef(_, typeParams2, paramss2, tpt2, Some(rhs2))) =>
val bindMatch =
if (hasBindAnnotation(pattern.symbol)) bindingMatch(scrutinee.symbol)
else matched
def rhsEnv =
val oldEnv: Env = summon[Env]
val newEnv: List[(Symbol, Symbol)] =
(scrutinee.symbol -> pattern.symbol) :: typeParams1.zip(typeParams2).map((tparam1, tparam2) => tparam1.symbol -> tparam2.symbol) :::
paramss1.flatten.zip(paramss2.flatten).map((param1, param2) => param1.symbol -> param2.symbol)
oldEnv ++ newEnv

bindMatch &&
typeParams1 =?= typeParams2 &&
matchLists(paramss1, paramss2)(_ =?= _) &&
tpt1 =?= tpt2 &&
withEnv(rhsEnv)(rhs1 =?= rhs2)
typeParams1 =?= typeParams2
&& matchLists(paramss1, paramss2)(_ =?= _)
&& tpt1 =?= tpt2
&& withEnv(rhsEnv)(rhs1 =?= rhs2)

case (Closure(_, tpt1), Closure(_, tpt2)) =>
// TODO match tpt1 with tpt2?
Expand Down
3 changes: 0 additions & 3 deletions library/src/scala/tasty/reflect/CompilerInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1497,9 +1497,6 @@ trait CompilerInterface {
/** Symbol of scala.internal.Quoted.patternHole */
def Definitions_InternalQuoted_patternHole: Symbol

/** Symbol of scala.internal.Quoted.patternBindHole */
def Definitions_InternalQuoted_patternBindHoleAnnot: Symbol

/** Symbol of scala.internal.Quoted.patternType */
def Definitions_InternalQuoted_patternTypeAnnot: Symbol

Expand Down
18 changes: 6 additions & 12 deletions tests/pos/quotedPatterns.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,17 @@ object Test {
case '{ ((a: Int) => 3)($y) } => y
case '{ 1 + ($y: Int)} => y
case '{ val a = 1 + ($y: Int); 3 } => y
case '{ val $y: Int = $z; println(`$y`); 1 } =>
val a: String = y
case '{ val y: Int = $z; println(y); 1 } =>
z
case '{ (($y: Int) => 1 + `$y` + ($z: Int))(2) } =>
val a: String = y
case '{ ((y: Int) => 1 + y + ($z: Int))(2) } =>
z
case '{ def $ff: Int = $z; `$ff` } =>
val a: String = ff
case '{ def ff: Int = $z; ff } =>
z
case '{ def $ff(i: Int): Int = $z; 2 } =>
val a: String = ff
case '{ def ff(i: Int): Int = $z; 2 } =>
z
case '{ def $ff(i: Int)(j: Int): Int = $z; 2 } =>
val a: String = ff
case '{ def ff(i: Int)(j: Int): Int = $z; 2 } =>
z
case '{ def $ff[T](i: T): Int = $z; 2 } =>
val a: String = ff
case '{ def ff[T](i: T): Int = $z; 2 } =>
z
case '{ poly[$t]($x); 4 } => ???
case '{ type $X; poly[`$X`]($x); 4 } => ???
Expand Down
30 changes: 15 additions & 15 deletions tests/run-macros/quote-matcher-runtime.check
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ Pattern: scala.internal.quoted.CompileTime.patternHole[scala.Function1[scala.Int
Result: Some(List(Expr(((x: scala.Int) => "abc"))))

Scrutinee: ((x: scala.Int) => "abc")
Pattern: ((x: scala.Int @scala.internal.quoted.CompileTime.patternBindHole) => scala.internal.quoted.CompileTime.patternHole[scala.Predef.String])
Result: Some(List(String(x), Expr("abc")))
Pattern: ((x: scala.Int) => scala.internal.quoted.CompileTime.patternHole[scala.Predef.String])
Result: Some(List(Expr("abc")))

Scrutinee: scala.StringContext.apply("abc", "xyz")
Pattern: scala.StringContext.apply("abc", "xyz")
Expand Down Expand Up @@ -267,10 +267,10 @@ Scrutinee: {
()
}
Pattern: {
@scala.internal.quoted.CompileTime.patternBindHole val a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
val a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
()
}
Result: Some(List(String(a), Expr(45)))
Result: Some(List(Expr(45)))

Scrutinee: {
val a: scala.Int = 45
Expand All @@ -297,7 +297,7 @@ Scrutinee: {
()
}
Pattern: {
@scala.internal.quoted.CompileTime.patternBindHole var a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
var a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
()
}
Result: None
Expand Down Expand Up @@ -369,7 +369,7 @@ Scrutinee: {
()
}
Pattern: {
@scala.internal.quoted.CompileTime.patternBindHole val a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
val a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
()
}
Result: None
Expand All @@ -379,7 +379,7 @@ Scrutinee: {
()
}
Pattern: {
@scala.internal.quoted.CompileTime.patternBindHole var a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
var a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
()
}
Result: None
Expand Down Expand Up @@ -419,7 +419,7 @@ Scrutinee: {
()
}
Pattern: {
@scala.internal.quoted.CompileTime.patternBindHole val a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
val a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
()
}
Result: None
Expand All @@ -429,7 +429,7 @@ Scrutinee: {
()
}
Pattern: {
@scala.internal.quoted.CompileTime.patternBindHole lazy val a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
lazy val a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
()
}
Result: None
Expand Down Expand Up @@ -499,10 +499,10 @@ Scrutinee: {
()
}
Pattern: {
@scala.internal.quoted.CompileTime.patternBindHole def a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
def a: scala.Int = scala.internal.quoted.CompileTime.patternHole[scala.Int]
()
}
Result: Some(List(String(a), Expr(45)))
Result: Some(List(Expr(45)))

Scrutinee: {
def a(x: scala.Int): scala.Int = 45
Expand Down Expand Up @@ -569,20 +569,20 @@ Scrutinee: {
()
}
Pattern: {
def a(x: scala.Int @scala.internal.quoted.CompileTime.patternBindHole): scala.Int = 45
def a(x: scala.Int): scala.Int = 45
()
}
Result: Some(List(String(x)))
Result: Some(List())

Scrutinee: {
def a(x: scala.Int): scala.Int = 45
()
}
Pattern: {
def a(x: scala.Int @scala.internal.quoted.CompileTime.patternBindHole): scala.Int = 45
def a(x: scala.Int): scala.Int = 45
()
}
Result: Some(List(String(x)))
Result: Some(List())

Scrutinee: {
def a(x: scala.Int): scala.Int = x
Expand Down
20 changes: 10 additions & 10 deletions tests/run-macros/quote-matcher-runtime/quoted_2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,43 +81,43 @@ object Test {
matches((() => "abc")(), (patternHole[() => String]).apply())
matches((x: Int) => "abc", patternHole[Int=> String])
matches(((x: Int) => "abc")(4), (patternHole[Int => String]).apply(4))
matches((x: Int) => "abc", (x: Int @patternBindHole) => patternHole[String])
matches((x: Int) => "abc", (x: Int) => patternHole[String])
matches(StringContext("abc", "xyz"), StringContext("abc", "xyz"))
matches(StringContext("abc", "xyz"), StringContext(patternHole, patternHole))
matches(StringContext("abc", "xyz"), StringContext(patternHole[Seq[String]]: _*))
matches({ val a: Int = 45 }, { val a: Int = 45 })
matches({ val a: Int = 45 }, { @patternBindHole val a: Int = patternHole })
matches({ val a: Int = 45 }, { val a: Int = patternHole })
matches({ val a: Int = 45 }, { lazy val a: Int = 45 })
matches({ val a: Int = 45 }, { var a: Int = 45 })
matches({ val a: Int = 45 }, { @patternBindHole var a: Int = patternHole })
matches({ val a: Int = 45 }, { var a: Int = patternHole })
matches({ val a: Int = 45; a + a }, { val x: Int = 45; x + x })
matches({ val a: Int = 45; val b = a }, { val x: Int = 45; val y = x })
matches({ val a: Int = 45; a + a }, { val x: Int = 45; x + patternHole[Int] })
matches({ lazy val a: Int = 45 }, { val a: Int = 45 })
matches({ lazy val a: Int = 45 }, { lazy val a: Int = 45 })
matches({ lazy val a: Int = 45 }, { var a: Int = 45 })
matches({ lazy val a: Int = 45 }, { @patternBindHole val a: Int = patternHole })
matches({ lazy val a: Int = 45 }, { @patternBindHole var a: Int = patternHole })
matches({ lazy val a: Int = 45 }, { val a: Int = patternHole })
matches({ lazy val a: Int = 45 }, { var a: Int = patternHole })
matches({ var a: Int = 45 }, { val a: Int = 45 })
matches({ var a: Int = 45 }, { lazy val a: Int = 45 })
matches({ var a: Int = 45 }, { var a: Int = 45 })
matches({ var a: Int = 45 }, { @patternBindHole val a: Int = patternHole })
matches({ var a: Int = 45 }, { @patternBindHole lazy val a: Int = patternHole })
matches({ var a: Int = 45 }, { val a: Int = patternHole })
matches({ var a: Int = 45 }, { lazy val a: Int = patternHole })
matches({ println(); println() }, { println(); println() })
matches({ { println() }; println() }, { println(); println() })
matches({ println(); { println() } }, { println(); println() })
matches({ println(); println() }, { println(); { println() } })
matches({ println(); println() }, { { println() }; println() })
matches({ def a: Int = 45 }, { def a: Int = 45 })
matches({ def a: Int = 45 }, { @patternBindHole def a: Int = patternHole[Int] })
matches({ def a: Int = 45 }, { def a: Int = patternHole[Int] })
matches({ def a(x: Int): Int = 45 }, { def a(x: Int): Int = 45 })
matches({ def a(x: Int): Int = 45 }, { def a(x: Int, y: Int): Int = 45 })
matches({ def a(x: Int): Int = 45 }, { def a(x: Int)(y: Int): Int = 45 })
matches({ def a(x: Int, y: Int): Int = 45 }, { def a(x: Int): Int = 45 })
matches({ def a(x: Int)(y: Int): Int = 45 }, { def a(x: Int): Int = 45 })
matches({ def a(x: String): Int = 45 }, { def a(x: String): Int = 45 })
matches({ def a(x: Int): Int = 45 }, { def a(x: Int @patternBindHole): Int = 45 })
matches({ def a(x: Int): Int = 45 }, { def a(x: Int @patternBindHole): Int = 45 })
matches({ def a(x: Int): Int = 45 }, { def a(x: Int): Int = 45 })
matches({ def a(x: Int): Int = 45 }, { def a(x: Int): Int = 45 })
matches({ def a(x: Int): Int = x }, { def b(y: Int): Int = y })
matches({ def a: Int = a }, { def b: Int = b })
matches({ def a: Int = a; a + a }, { def a: Int = a; a + a })
Expand Down