@@ -1964,13 +1964,50 @@ class Typer extends Namer
1964
1964
val exprPt = pt.baseType(defn.QuotedExprClass )
1965
1965
val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType
1966
1966
val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode .QuotedPattern ))
1967
- val (shape, splices) = splitQuotePattern(quoted1)
1968
- val patType = defn.tupleType(splices.tpes.map(_.widen))
1969
- val splicePat = typed(untpd.Tuple (splices.map(untpd.TypedSplice (_))).withSpan(quoted.span), patType)
1967
+ val (typeBindings, shape, splices) = splitQuotePattern(quoted1)
1968
+
1969
+ class ReplaceBindings extends TypeMap () {
1970
+ override def apply (tp : Type ): Type = tp match {
1971
+ case tp : TypeRef =>
1972
+ val tp1 = if (tp.typeSymbol == defn.QuotedType_splice ) tp.dealias else tp
1973
+ typeBindings.get(tp1.typeSymbol).fold(tp)(_.symbol.typeRef)
1974
+ case tp => mapOver(tp)
1975
+ }
1976
+ }
1977
+ val replaceBindings = new ReplaceBindings
1978
+ val patType = defn.tupleType(splices.tpes.map(tpe => replaceBindings(tpe.widen)))
1979
+
1980
+ val typeBindingsTuple = tpd.tupleTypeTree(typeBindings.values.toList)
1981
+
1982
+ val replaceBindingsInTree = new TreeMap {
1983
+ private [this ] var bindMap = Map .empty[Symbol , Symbol ]
1984
+ override def transform (tree : tpd.Tree )(implicit ctx : Context ): tpd.Tree = {
1985
+ tree match {
1986
+ case tree : Bind =>
1987
+ val sym = tree.symbol
1988
+ val newInfo = replaceBindings(sym.info)
1989
+ val newSym = ctx.newSymbol(sym.owner, sym.name, sym.flags, newInfo, sym.privateWithin, sym.coord)
1990
+ bindMap += sym -> newSym
1991
+ Bind (newSym, transform(tree.body)).withSpan(sym.span)
1992
+ case _ =>
1993
+ super .transform(tree).withType(replaceBindingsInType(tree.tpe))
1994
+ }
1995
+ }
1996
+ private [this ] val replaceBindingsInType = new ReplaceBindings {
1997
+ override def apply (tp : Type ): Type = tp match {
1998
+ case tp : TermRef => bindMap.get(tp.termSymbol).fold(tp)(_.typeRef)
1999
+ case tp => super .apply(tp)
2000
+ }
2001
+ }
2002
+ }
2003
+
2004
+ val splicePat = typed(untpd.Tuple (splices.map(x => untpd.TypedSplice (replaceBindingsInTree.transform(x)))).withSpan(quoted.span), patType)
2005
+
1970
2006
UnApply (
1971
- fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToType( patType),
2007
+ fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToTypeTrees(typeBindingsTuple :: TypeTree ( patType) :: Nil ),
1972
2008
implicits =
1973
2009
ref(defn.InternalQuoted_exprQuoteR ).appliedToType(shape.tpe).appliedTo(shape) ::
2010
+ Literal (Constant (typeBindings.nonEmpty)) ::
1974
2011
implicitArgTree(defn.TastyReflectionType , tree.span) :: Nil ,
1975
2012
patterns = splicePat :: Nil ,
1976
2013
proto = pt)
@@ -1980,8 +2017,25 @@ class Typer extends Namer
1980
2017
}
1981
2018
}
1982
2019
1983
- def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (Tree , List [Tree ]) = {
2020
+ def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (Map [ Symbol , Bind ], Tree , List [Tree ]) = {
1984
2021
val ctx0 = ctx
2022
+
2023
+ val typeBindings : collection.mutable.Map [Symbol , Bind ] = collection.mutable.Map .empty
2024
+ val freshTypeBindingsBuff = List .newBuilder[Tree ]
2025
+ def getBinding (sym : Symbol ): Bind =
2026
+ typeBindings.getOrElseUpdate(sym, {
2027
+ val bindingBounds = sym.info
2028
+ val bsym = ctx.newPatternBoundSymbol(sym.name.toTypeName, bindingBounds, quoted.span)
2029
+ Bind (bsym, untpd.Ident (nme.WILDCARD ).withType(bindingBounds)).withSpan(quoted.span)
2030
+ })
2031
+ def replaceTypeBindings = new TypeMap {
2032
+ def apply (tp : Type ): Type = tp match {
2033
+ case tp : TypeRef if tp.typeSymbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot ) =>
2034
+ getBinding(tp.typeSymbol).symbol.typeRef
2035
+ case _ => mapOver(tp)
2036
+ }
2037
+ }
2038
+
1985
2039
object splitter extends tpd.TreeMap {
1986
2040
val patBuf = new mutable.ListBuffer [Tree ]
1987
2041
override def transform (tree : Tree )(implicit ctx : Context ) = tree match {
@@ -1996,6 +2050,12 @@ class Typer extends Namer
1996
2050
val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
1997
2051
patBuf += pat1
1998
2052
}
2053
+ case Select (pat, _) if tree.symbol == defn.QuotedType_splice =>
2054
+ val sym = tree.tpe.dealias.typeSymbol.asType
2055
+ val tdef = TypeDef (sym).withSpan(sym.span)
2056
+ freshTypeBindingsBuff += transformTypeBindingTypeDef(tdef)
2057
+ TypeTree (tree.tpe.dealias).withSpan(tree.span)
2058
+
1999
2059
case ddef : ValOrDefDef =>
2000
2060
if (ddef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot )) {
2001
2061
val bindingType = ddef.symbol.info match {
@@ -2014,17 +2074,54 @@ class Typer extends Namer
2014
2074
patBuf += Bind (sym, untpd.Ident (nme.WILDCARD ).withType(bindingExprTpe)).withSpan(ddef.span)
2015
2075
}
2016
2076
super .transform(tree)
2077
+ case tdef : TypeDef if tdef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot ) =>
2078
+ transformTypeBindingTypeDef(tdef)
2017
2079
case _ =>
2018
2080
super .transform(tree)
2019
2081
}
2082
+
2083
+ def transformTypeBindingTypeDef (tdef : TypeDef ): Tree = {
2084
+ val bindingType = getBinding(tdef.symbol).symbol.typeRef
2085
+ val bindingTypeTpe = AppliedType (defn.QuotedTypeType , bindingType :: Nil )
2086
+ assert(tdef.name.startsWith(" $" ))
2087
+ val bindName = tdef.name.toString.stripPrefix(" $" ).toTermName
2088
+ val sym = ctx0.newPatternBoundSymbol(bindName, bindingTypeTpe, tdef.span)
2089
+ patBuf += Bind (sym, untpd.Ident (nme.WILDCARD ).withType(bindingTypeTpe)).withSpan(tdef.span)
2090
+ super .transform(tdef)
2091
+ }
2020
2092
}
2021
- val result = splitter.transform(quoted)
2022
- (result, splitter.patBuf.toList)
2093
+ val shape0 = splitter.transform(quoted)
2094
+ val patterns = splitter.patBuf.toList
2095
+ val freshTypeBindings = freshTypeBindingsBuff.result()
2096
+
2097
+ val shape1 = seq(
2098
+ freshTypeBindings,
2099
+ shape0
2100
+ )
2101
+ val shape2 = {
2102
+ if (freshTypeBindings.isEmpty) shape1
2103
+ else {
2104
+ val isFreshTypeBindings = freshTypeBindings.map(_.symbol).toSet
2105
+ new TreeTypeMap (
2106
+ typeMap = {
2107
+ case tp : TypeRef if tp.typeSymbol == defn.QuotedType_splice =>
2108
+ val tp1 = tp.dealias
2109
+ if (isFreshTypeBindings(tp1.typeSymbol)) tp1
2110
+ else tp
2111
+ case tp => tp
2112
+ }
2113
+ ).transform(shape1)
2114
+ }
2115
+ }
2116
+
2117
+ (typeBindings.toMap, shape2, patterns)
2023
2118
}
2024
2119
2025
2120
/** A hole the shape pattern of a quoted.Matcher.unapply, representing a splice */
2026
- def patternHole (splice : Tree )(implicit ctx : Context ): Tree =
2121
+ def patternHole (splice : Tree )(implicit ctx : Context ): Tree = {
2122
+ val Splice (pat) = splice
2027
2123
ref(defn.InternalQuoted_patternHoleR ).appliedToType(splice.tpe).withSpan(splice.span)
2124
+ }
2028
2125
2029
2126
/** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */
2030
2127
def typedSplice (tree : untpd.Splice , pt : Type )(implicit ctx : Context ): Tree = track(" typedSplice" ) {
@@ -2070,7 +2167,28 @@ class Typer extends Namer
2070
2167
ctx.warning(" Canceled quote directly inside a splice. ${ '[ XYZ ] } is equivalent to XYZ." , tree.sourcePos)
2071
2168
typed(innerType, pt)
2072
2169
case expr =>
2073
- typedSelect(untpd.Select (tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span)
2170
+ if (ctx.mode.is(Mode .QuotedPattern ) && level == 1 ) {
2171
+ if (isFullyDefined(pt, ForceDegree .all)) {
2172
+ ctx.error(i " Spliced type pattern must not be fully defined. Consider using $pt directly " , tree.expr.sourcePos)
2173
+ tree.withType(UnspecifiedErrorType )
2174
+ } else {
2175
+ def spliceOwner (ctx : Context ): Symbol =
2176
+ if (ctx.mode.is(Mode .QuotedPattern )) spliceOwner(ctx.outer) else ctx.owner
2177
+ val name = expr match {
2178
+ case Ident (name) => (" $" + name).toTypeName
2179
+ case Typed (Ident (name), _) => (" $" + name).toTypeName
2180
+ case Bind (name, _) => (" $" + name).toTypeName
2181
+ case _ => NameKinds .UniqueName .fresh(" $" .toTypeName)
2182
+ }
2183
+ val typeSym = ctx.newSymbol(spliceOwner(ctx), name, EmptyFlags , TypeBounds .empty, NoSymbol , expr.span)
2184
+ typeSym.addAnnotation(Annotation (New (ref(defn.InternalQuoted_patternBindHoleAnnot .typeRef)).withSpan(expr.span)))
2185
+ val pat = typedPattern(expr, defn.QuotedTypeType .appliedTo(typeSym.typeRef))(
2186
+ spliceContext.retractMode(Mode .QuotedPattern ).withOwner(spliceOwner(ctx)))
2187
+ pat.select(tpnme.splice)
2188
+ }
2189
+ } else {
2190
+ typedSelect(untpd.Select (tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span)
2191
+ }
2074
2192
}
2075
2193
}
2076
2194
0 commit comments