@@ -1975,13 +1975,51 @@ class Typer extends Namer
19751975 val exprPt = pt.baseType(defn.QuotedExprClass )
19761976 val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType
19771977 val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode .QuotedPattern ))
1978- val (shape, splices) = splitQuotePattern(quoted1)
1979- val patType = defn.tupleType(splices.tpes.map(_.widen))
1980- val splicePat = typed(untpd.Tuple (splices.map(untpd.TypedSplice (_))).withSpan(quoted.span), patType)
1978+
1979+ val (typeBindings, shape, splices) = splitQuotePattern(quoted1)
1980+
1981+ class ReplaceBindings extends TypeMap () {
1982+ override def apply (tp : Type ): Type = tp match {
1983+ case tp : TypeRef =>
1984+ val tp1 = if (tp.typeSymbol == defn.QuotedType_splice ) tp.dealias else tp
1985+ typeBindings.get(tp1.typeSymbol).fold(tp)(_.symbol.typeRef)
1986+ case tp => mapOver(tp)
1987+ }
1988+ }
1989+ val replaceBindings = new ReplaceBindings
1990+ val patType = defn.tupleType(splices.tpes.map(tpe => replaceBindings(tpe.widen)))
1991+
1992+ val typeBindingsTuple = tpd.tupleTypeTree(typeBindings.values.toList)
1993+
1994+ val replaceBindingsInTree = new TreeMap {
1995+ private [this ] var bindMap = Map .empty[Symbol , Symbol ]
1996+ override def transform (tree : tpd.Tree )(implicit ctx : Context ): tpd.Tree = {
1997+ tree match {
1998+ case tree : Bind =>
1999+ val sym = tree.symbol
2000+ val newInfo = replaceBindings(sym.info)
2001+ val newSym = ctx.newSymbol(sym.owner, sym.name, sym.flags, newInfo, sym.privateWithin, sym.coord)
2002+ bindMap += sym -> newSym
2003+ Bind (newSym, transform(tree.body)).withSpan(sym.span)
2004+ case _ =>
2005+ super .transform(tree).withType(replaceBindingsInType(tree.tpe))
2006+ }
2007+ }
2008+ private [this ] val replaceBindingsInType = new ReplaceBindings {
2009+ override def apply (tp : Type ): Type = tp match {
2010+ case tp : TermRef => bindMap.get(tp.termSymbol).fold[Type ](tp)(_.typeRef)
2011+ case tp => super .apply(tp)
2012+ }
2013+ }
2014+ }
2015+
2016+ val splicePat = typed(untpd.Tuple (splices.map(x => untpd.TypedSplice (replaceBindingsInTree.transform(x)))).withSpan(quoted.span), patType)
2017+
19812018 UnApply (
1982- fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToType( patType),
2019+ fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToTypeTrees(typeBindingsTuple :: TypeTree ( patType) :: Nil ),
19832020 implicits =
19842021 ref(defn.InternalQuoted_exprQuoteR ).appliedToType(shape.tpe).appliedTo(shape) ::
2022+ Literal (Constant (typeBindings.nonEmpty)) ::
19852023 implicitArgTree(defn.TastyReflectionType , tree.span) :: Nil ,
19862024 patterns = splicePat :: Nil ,
19872025 proto = pt)
@@ -1991,13 +2029,26 @@ class Typer extends Namer
19912029 }
19922030 }
19932031
1994- def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (Tree , List [Tree ]) = {
2032+ def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (Map [ Symbol , Bind ], Tree , List [Tree ]) = {
19952033 val ctx0 = ctx
2034+
2035+ val typeBindings : collection.mutable.Map [Symbol , Bind ] = collection.mutable.Map .empty
2036+ def getBinding (sym : Symbol ): Bind =
2037+ typeBindings.getOrElseUpdate(sym, {
2038+ val bindingBounds = sym.info
2039+ val bsym = ctx.newPatternBoundSymbol(sym.name.toTypeName, bindingBounds, quoted.span)
2040+ Bind (bsym, untpd.Ident (nme.WILDCARD ).withType(bindingBounds)).withSpan(quoted.span)
2041+ })
2042+
19962043 object splitter extends tpd.TreeMap {
19972044 val patBuf = new mutable.ListBuffer [Tree ]
2045+ val freshTypePatBuf = new mutable.ListBuffer [Tree ]
2046+ val freshTypeBindingsBuff = new mutable.ListBuffer [Tree ]
2047+ val typePatBuf = new mutable.ListBuffer [Tree ]
19982048 override def transform (tree : Tree )(implicit ctx : Context ) = tree match {
19992049 case Typed (Splice (pat), tpt) if ! tpt.tpe.derivesFrom(defn.RepeatedParamClass ) =>
2000- val exprTpt = AppliedTypeTree (TypeTree (defn.QuotedExprType ), tpt :: Nil )
2050+ val tpt1 = transform(tpt) // Transform type bindings
2051+ val exprTpt = AppliedTypeTree (TypeTree (defn.QuotedExprType ), tpt1 :: Nil )
20012052 transform(Splice (Typed (pat, exprTpt)))
20022053 case Splice (pat) =>
20032054 try patternHole(tree)
@@ -2007,6 +2058,12 @@ class Typer extends Namer
20072058 val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
20082059 patBuf += pat1
20092060 }
2061+ case Select (pat, _) if tree.symbol == defn.QuotedType_splice =>
2062+ val sym = tree.tpe.dealias.typeSymbol.asType
2063+ val tdef = TypeDef (sym).withSpan(sym.span)
2064+ freshTypeBindingsBuff += transformTypeBindingTypeDef(tdef, freshTypePatBuf)
2065+ TypeTree (tree.tpe.dealias).withSpan(tree.span)
2066+
20102067 case ddef : ValOrDefDef =>
20112068 if (ddef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot )) {
20122069 val bindingType = ddef.symbol.info match {
@@ -2025,17 +2082,55 @@ class Typer extends Namer
20252082 patBuf += Bind (sym, untpd.Ident (nme.WILDCARD ).withType(bindingExprTpe)).withSpan(ddef.span)
20262083 }
20272084 super .transform(tree)
2085+ case tdef : TypeDef if tdef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot ) =>
2086+ transformTypeBindingTypeDef(tdef, typePatBuf)
20282087 case _ =>
20292088 super .transform(tree)
20302089 }
2090+
2091+ def transformTypeBindingTypeDef (tdef : TypeDef , buff : mutable.Builder [Tree , List [Tree ]]): Tree = {
2092+ val bindingType = getBinding(tdef.symbol).symbol.typeRef
2093+ val bindingTypeTpe = AppliedType (defn.QuotedTypeType , bindingType :: Nil )
2094+ assert(tdef.name.startsWith(" $" ))
2095+ val bindName = tdef.name.toString.stripPrefix(" $" ).toTermName
2096+ val sym = ctx0.newPatternBoundSymbol(bindName, bindingTypeTpe, tdef.span, flags = ImplicitTerm )
2097+ buff += Bind (sym, untpd.Ident (nme.WILDCARD ).withType(bindingTypeTpe)).withSpan(tdef.span)
2098+ super .transform(tdef)
2099+ }
2100+ }
2101+ val shape0 = splitter.transform(quoted)
2102+ val patterns = (splitter.freshTypePatBuf.iterator ++ splitter.typePatBuf.iterator ++ splitter.patBuf.iterator).toList
2103+ val freshTypeBindings = splitter.freshTypeBindingsBuff.result()
2104+
2105+ val shape1 = seq(
2106+ freshTypeBindings,
2107+ shape0
2108+ )
2109+ val shape2 = {
2110+ if (freshTypeBindings.isEmpty) shape1
2111+ else {
2112+ val isFreshTypeBindings = freshTypeBindings.map(_.symbol).toSet
2113+ val typeMap = new TypeMap () {
2114+ def apply (tp : Type ): Type = tp match {
2115+ case tp : TypeRef if tp.typeSymbol == defn.QuotedType_splice =>
2116+ val tp1 = tp.dealias
2117+ if (isFreshTypeBindings(tp1.typeSymbol)) tp1
2118+ else tp
2119+ case tp => mapOver(tp)
2120+ }
2121+ }
2122+ new TreeTypeMap (typeMap = typeMap).transform(shape1)
2123+ }
20312124 }
2032- val result = splitter.transform(quoted)
2033- (result, splitter.patBuf.toList )
2125+
2126+ (typeBindings.toMap, shape2, patterns )
20342127 }
20352128
20362129 /** A hole the shape pattern of a quoted.Matcher.unapply, representing a splice */
2037- def patternHole (splice : Tree )(implicit ctx : Context ): Tree =
2130+ def patternHole (splice : Tree )(implicit ctx : Context ): Tree = {
2131+ val Splice (pat) = splice
20382132 ref(defn.InternalQuoted_patternHoleR ).appliedToType(splice.tpe).withSpan(splice.span)
2133+ }
20392134
20402135 /** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */
20412136 def typedSplice (tree : untpd.Splice , pt : Type )(implicit ctx : Context ): Tree = track(" typedSplice" ) {
@@ -2081,7 +2176,28 @@ class Typer extends Namer
20812176 ctx.warning(" Canceled quote directly inside a splice. ${ '[ XYZ ] } is equivalent to XYZ." , tree.sourcePos)
20822177 typed(innerType, pt)
20832178 case expr =>
2084- typedSelect(untpd.Select (tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span)
2179+ if (ctx.mode.is(Mode .QuotedPattern ) && level == 1 ) {
2180+ if (isFullyDefined(pt, ForceDegree .all)) {
2181+ ctx.error(i " Spliced type pattern must not be fully defined. Consider using $pt directly " , tree.expr.sourcePos)
2182+ tree.withType(UnspecifiedErrorType )
2183+ } else {
2184+ def spliceOwner (ctx : Context ): Symbol =
2185+ if (ctx.mode.is(Mode .QuotedPattern )) spliceOwner(ctx.outer) else ctx.owner
2186+ val name = expr match {
2187+ case Ident (name) => (" $" + name).toTypeName
2188+ case Typed (Ident (name), _) => (" $" + name).toTypeName
2189+ case Bind (name, _) => (" $" + name).toTypeName
2190+ case _ => NameKinds .UniqueName .fresh(" $" .toTypeName)
2191+ }
2192+ val typeSym = ctx.newSymbol(spliceOwner(ctx), name, EmptyFlags , TypeBounds .empty, NoSymbol , expr.span)
2193+ typeSym.addAnnotation(Annotation (New (ref(defn.InternalQuoted_patternBindHoleAnnot .typeRef)).withSpan(expr.span)))
2194+ val pat = typedPattern(expr, defn.QuotedTypeType .appliedTo(typeSym.typeRef))(
2195+ spliceContext.retractMode(Mode .QuotedPattern ).withOwner(spliceOwner(ctx)))
2196+ pat.select(tpnme.splice)
2197+ }
2198+ } else {
2199+ typedSelect(untpd.Select (tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span)
2200+ }
20852201 }
20862202 }
20872203
0 commit comments