Skip to content

Commit 7ae170b

Browse files
committed
WIP
1 parent bc5525b commit 7ae170b

File tree

8 files changed

+135
-83
lines changed

8 files changed

+135
-83
lines changed

Foo.scala

Lines changed: 0 additions & 32 deletions
This file was deleted.

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,24 @@ object desugar {
829829
Thicket(aliasType :: companions.toList)
830830
}
831831

832+
/** Transforms
833+
*
834+
* <mods> type $T >: Low <: Hi
835+
*
836+
* to
837+
*
838+
* @patternBindHole <mods> type $T >: Low <: Hi
839+
*
840+
* if the type is a type splice.
841+
*/
842+
def quotedPatternTypeDef(tree: TypeDef)(implicit ctx: Context): TypeDef = {
843+
assert(ctx.mode.is(Mode.QuotedPattern))
844+
if (tree.name.startsWith("$") /* && !tree.isBackQuoted*/) { // TODO add backquoted TypeDef
845+
val mods = tree.mods.withAddedAnnotation(New(ref(defn.InternalQuoted_patternBindHoleAnnot.typeRef)).withSpan(tree.span))
846+
tree.withMods(mods)
847+
} else tree
848+
}
849+
832850
/** The normalized name of `mdef`. This means
833851
* 1. Check that the name does not redefine a Scala core class.
834852
* If it does redefine, issue an error and return a mangled name instead of the original one.
@@ -995,6 +1013,7 @@ object desugar {
9951013
case tree: TypeDef =>
9961014
if (tree.isClassDef) classDef(tree)
9971015
else if (tree.mods.is(Opaque, butNot = Synthetic)) opaqueAlias(tree)
1016+
else if (ctx.mode.is(Mode.QuotedPattern)) quotedPatternTypeDef(tree)
9981017
else tree
9991018
case tree: DefDef =>
10001019
if (tree.name.isConstructorName) tree // was already handled by enclosing classDef

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
13181318
}
13191319
}
13201320

1321+
/** Creates the tuple type tree repesentation of the type trees in `ts` */
1322+
def tupleTypeTree(elems: List[Tree])(implicit ctx: Context): Tree = {
1323+
val arity = elems.length
1324+
if (arity <= Definitions.MaxTupleArity && defn.TupleType(arity) != null) AppliedTypeTree(TypeTree(defn.TupleType(arity)), elems)
1325+
else nestedPairsType(elems)
1326+
}
1327+
1328+
/** Creates the nested pairs type tree repesentation of the type trees in `ts` */
1329+
def nestedPairsType(ts: List[Tree])(implicit ctx: Context): Tree =
1330+
ts.foldRight[Tree](TypeTree(defn.UnitType))((x, acc) => AppliedTypeTree(TypeTree(defn.PairType), x :: acc :: Nil))
1331+
13211332
/** Replaces all positions in `tree` with zero-extent positions */
13221333
private def focusPositions(tree: Tree)(implicit ctx: Context): Tree = {
13231334
val transformer = new tpd.TreeMap {

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,16 @@ class TreePickler(pickler: TastyPickler) {
472472
case Bind(name, body) =>
473473
registerDef(tree.symbol)
474474
writeByte(BIND)
475+
println()
476+
println(tree)
477+
println(tree.isTerm)
478+
println(name)
479+
println(body)
480+
println(tree.uniqueId)
481+
println(tree.symbol)
482+
println(tree.symbol.info)
483+
println()
484+
println()
475485
withLength {
476486
pickleName(name); pickleType(tree.symbol.info); pickleTree(body)
477487
}

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

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,23 +1943,29 @@ class Typer extends Namer
19431943
val exprPt = pt.baseType(defn.QuotedExprClass)
19441944
val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType
19451945
val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode.QuotedPattern))
1946-
val (shape, splices) = splitQuotePattern(quoted1)
1947-
val typeBindings = splices.collect {
1948-
case t if t.tpe.derivesFrom(defn.QuotedTypeClass) =>
1949-
t.tpe.widen.argTypesHi.head.typeSymbol
1950-
}
1951-
val inQuoteTypeBinding = typeBindings.map { sym =>
1952-
ctx.newSymbol(sym.owner, (sym.name + "$$$").toTypeName, // TODO remove $$$, just there for debugging
1953-
EmptyFlags, sym.info, coord = sym.coord)
1954-
}
1955-
val shape2 =
1956-
seq(inQuoteTypeBinding.map(TypeDef), shape.subst(typeBindings, inQuoteTypeBinding))
1946+
val (typeBindings, shape, splices) = splitQuotePattern(quoted1)
1947+
// val typeBindings = splices.collect {
1948+
// case t if t.tpe.derivesFrom(defn.QuotedTypeClass) =>
1949+
// t.tpe.widen.argTypesHi.head.typeSymbol
1950+
// }
1951+
// val inQuoteTypeBinding = typeBindings.map { sym =>
1952+
// ctx.newSymbol(sym.owner, (sym.name + "$$$").toTypeName, // TODO remove $$$, just there for debugging
1953+
// EmptyFlags, sym.info, coord = sym.coord)
1954+
// }
1955+
// val shape2 =
1956+
// seq(inQuoteTypeBinding.map(TypeDef), shape.subst(typeBindings, inQuoteTypeBinding))
1957+
1958+
19571959
val patType = defn.tupleType(splices.tpes.map(_.widen))
1960+
1961+
val typeBindingsTuple = tpd.tupleTypeTree(typeBindings)
1962+
19581963
val splicePat = typed(untpd.Tuple(splices.map(untpd.TypedSplice(_))).withSpan(quoted.span), patType)
1964+
19591965
UnApply(
1960-
fun = ref(defn.InternalQuotedMatcher_unapplyR).appliedToType(patType),
1966+
fun = ref(defn.InternalQuotedMatcher_unapplyR).appliedToTypeTrees(typeBindingsTuple :: TypeTree(patType) :: Nil),
19611967
implicits =
1962-
ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape2) ::
1968+
ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) ::
19631969
implicitArgTree(defn.TastyReflectionType, tree.span) :: Nil,
19641970
patterns = splicePat :: Nil,
19651971
proto = pt)
@@ -1969,8 +1975,22 @@ class Typer extends Namer
19691975
}
19701976
}
19711977

1972-
def splitQuotePattern(quoted: Tree)(implicit ctx: Context): (Tree, List[Tree]) = {
1978+
def splitQuotePattern(quoted: Tree)(implicit ctx: Context): (List[Bind], Tree, List[Tree]) = {
19731979
val ctx0 = ctx
1980+
1981+
val typeBindings: collection.mutable.Map[Symbol, Bind] = collection.mutable.Map.empty
1982+
def replaceTypeBindings = new TypeMap {
1983+
def apply(tp: Type): Type = tp match {
1984+
case tp: TypeRef if tp.typeSymbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot) =>
1985+
val bindingBounds = TypeBounds.apply(defn.NothingType, defn.AnyType) // TODO recover bounds
1986+
val sym = ctx.newPatternBoundSymbol((tp.name + "$").toTypeName, bindingBounds, quoted.span)
1987+
val bind = typeBindings.getOrElseUpdate(tp.typeSymbol,
1988+
Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingBounds)).withSpan(quoted.span))
1989+
bind.symbol.typeRef
1990+
case _ => mapOver(tp)
1991+
}
1992+
}
1993+
19741994
object splitter extends tpd.TreeMap {
19751995
val patBuf = new mutable.ListBuffer[Tree]
19761996
override def transform(tree: Tree)(implicit ctx: Context) = tree match {
@@ -1981,8 +2001,18 @@ class Typer extends Namer
19812001
try patternHole(tree)
19822002
finally {
19832003
val patType = pat.tpe.widen
1984-
val patType1 = patType.underlyingIfRepeated(isJava = false)
2004+
val patType1 = replaceTypeBindings(patType.underlyingIfRepeated(isJava = false))
19852005
val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
2006+
println("=-=-=-============-=-=-=----=-=-=")
2007+
println(pat)
2008+
println(pat.symbol)
2009+
println(pat.symbol.info)
2010+
println()
2011+
println(pat1)
2012+
println(pat1.symbol)
2013+
println(pat1.symbol.info)
2014+
println()
2015+
println()
19862016
patBuf += pat1
19872017
}
19882018
case ddef: ValOrDefDef =>
@@ -2008,7 +2038,7 @@ class Typer extends Namer
20082038
}
20092039
}
20102040
val result = splitter.transform(quoted)
2011-
(result, splitter.patBuf.toList)
2041+
(typeBindings.toList.map(_._2), result, splitter.patBuf.toList)
20122042
}
20132043

20142044
/** A hole the shape pattern of a quoted.Matcher.unapply, representing a splice */
@@ -2065,18 +2095,32 @@ class Typer extends Namer
20652095
case expr =>
20662096
if (ctx.mode.is(Mode.QuotedPattern) && level == 1) {
20672097
if (isFullyDefined(pt, ForceDegree.all)) {
2098+
// TODO is this error still relevant here? probably not
20682099
ctx.error(i"Type must be fully defined.\nConsider annotating the splice using a type ascription:\n ($tree: XYZ).", tree.expr.sourcePos)
20692100
tree.withType(UnspecifiedErrorType)
20702101
} else {
2071-
val bindingBounds = TypeBounds.apply(defn.NothingType, defn.AnyType)
2072-
val sym = ctx.newPatternBoundSymbol("ttt".toTypeName, bindingBounds, expr.span)
2073-
val bind = Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingBounds)).withSpan(expr.span)
2102+
expr match {
2103+
case Ident(name) => typedIdent(untpd.Ident(("$" + name).toTypeName), pt)
2104+
}
2105+
2106+
// println()
2107+
// println(expr)
2108+
// println()
2109+
// println()
2110+
// val bindingBounds = TypeBounds.apply(defn.NothingType, defn.AnyType)
2111+
// def getName(tree: untpd.Tree): TypeName = tree match {
2112+
// case tree: RefTree => ("$" + tree.name).toTypeName
2113+
// case tree: Typed => getName(tree.expr)
2114+
// }
2115+
// val sym = ctx.newPatternBoundSymbol(getName(expr), bindingBounds, expr.span)
2116+
// val bind = Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingBounds)).withSpan(expr.span)
2117+
//
2118+
// def spliceOwner(ctx: Context): Symbol =
2119+
// if (ctx.mode.is(Mode.QuotedPattern)) spliceOwner(ctx.outer) else ctx.owner
2120+
// val pat = typedPattern(tree.expr, defn.QuotedTypeType.appliedTo(sym.typeRef))(
2121+
// spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
2122+
// Splice(Typed(pat, AppliedTypeTree(TypeTree(defn.QuotedTypeType), bind :: Nil)))
20742123

2075-
def spliceOwner(ctx: Context): Symbol =
2076-
if (ctx.mode.is(Mode.QuotedPattern)) spliceOwner(ctx.outer) else ctx.owner
2077-
val pat = typedPattern(tree.expr, defn.QuotedTypeType.appliedTo(sym.typeRef))(
2078-
spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
2079-
Splice(Typed(pat, AppliedTypeTree(TypeTree(defn.QuotedTypeType), bind :: Nil)))
20802124
}
20812125

20822126
} else {

library/src-2.x/scala/internal/quoted/Matcher.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import scala.tasty.Reflection
55

66
object Matcher {
77

8-
def unapply[Tup <: Tuple](scrutineeExpr: Expr[_])(implicit patternExpr: Expr[_], reflection: Reflection): Option[Tup] =
8+
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeExpr: Expr[_])(implicit patternExpr: Expr[_], reflection: Reflection): Option[Tup] =
99
throw new Exception("running on non bootstrapped library")
1010

1111
}

library/src-3.x/scala/internal/quoted/Matcher.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ object Matcher {
3030
* @param reflection instance of the reflection API (implicitly provided by the macro)
3131
* @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Expr[Ti]``
3232
*/
33-
def unapply[Tup <: Tuple](scrutineeExpr: Expr[_])(implicit patternExpr: Expr[_], reflection: Reflection): Option[Tup] = {
33+
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeExpr: Expr[_])(implicit patternExpr: Expr[_], reflection: Reflection): Option[Tup] = {
3434
import reflection.{Bind => BindPattern, _}
3535

3636
// TODO improve performance

tests/pos/quotedPatterns.scala

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,32 @@ object Test {
66
// def g(x: Int, y: Int) = x * y
77

88
def res given tasty.Reflection: quoted.Expr[Int] = x match {
9-
case '{1 + 2} => '{0}
10-
case '{f($y)} => y
11-
case '{g($y, $z)} => '{$y * $z}
12-
case '{ ((a: Int) => 3)($y) } => y
13-
case '{ 1 + ($y: Int)} => y
14-
case '{ val a = 1 + ($y: Int); 3 } => y
15-
case '{ val $y: Int = $z; println(`$y`); 1 } =>
16-
val a: quoted.matching.Bind[Int] = y
17-
z
18-
case '{ (($y: Int) => 1 + `$y` + ($z: Int))(2) } =>
19-
val a: quoted.matching.Bind[Int] = y
20-
z
21-
case '{ def $ff: Int = $z; `$ff` } =>
22-
val a: quoted.matching.Bind[Int] = ff
23-
z
24-
case '{ def $ff(i: Int): Int = $z; 2 } =>
25-
val a: quoted.matching.Bind[Int => Int] = ff
26-
z
27-
case '{ def $ff(i: Int)(j: Int): Int = $z; 2 } =>
28-
val a: quoted.matching.Bind[Int => Int => Int] = ff
29-
z
30-
case '{ def $ff[T](i: T): Int = $z; 2 } =>
31-
val a: quoted.matching.Bind[[T] => T => Int] = ff
32-
z
9+
// case '{1 + 2} => '{0}
10+
// case '{f($y)} => y
11+
// case '{g($y, $z)} => '{$y * $z}
12+
// case '{ ((a: Int) => 3)($y) } => y
13+
// case '{ 1 + ($y: Int)} => y
14+
// case '{ val a = 1 + ($y: Int); 3 } => y
15+
// case '{ val $y: Int = $z; println(`$y`); 1 } =>
16+
// val a: quoted.matching.Bind[Int] = y
17+
// z
18+
// case '{ (($y: Int) => 1 + `$y` + ($z: Int))(2) } =>
19+
// val a: quoted.matching.Bind[Int] = y
20+
// z
21+
// case '{ def $ff: Int = $z; `$ff` } =>
22+
// val a: quoted.matching.Bind[Int] = ff
23+
// z
24+
// case '{ def $ff(i: Int): Int = $z; 2 } =>
25+
// val a: quoted.matching.Bind[Int => Int] = ff
26+
// z
27+
// case '{ def $ff(i: Int)(j: Int): Int = $z; 2 } =>
28+
// val a: quoted.matching.Bind[Int => Int => Int] = ff
29+
// z
30+
// case '{ def $ff[T](i: T): Int = $z; 2 } =>
31+
// val a: quoted.matching.Bind[[T] => T => Int] = ff
32+
// z
3333
// case '{ poly[$t]($x); 2 } => ???
34-
case '{ val x: $t = $x; (${scala.quoted.matching.Bind(t2)}: x.type); 4 } if t == t2 => ???
34+
case '{ type $T; val x: $T = $a; val y: $T = x; 1 } => ???
3535
case _ => '{1}
3636
}
3737

0 commit comments

Comments
 (0)