@@ -1964,11 +1964,49 @@ class Typer extends Namer
19641964 val exprPt = pt.baseType(defn.QuotedExprClass )
19651965 val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType
19661966 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+ typeBindings.get(tp.typeSymbol).fold(tp)(_.symbol.typeRef)
1973+ case tp => mapOver(tp)
1974+ }
1975+ }
1976+ val replaceBindings = new ReplaceBindings
1977+ val patType = defn.tupleType(splices.tpes.map(tpe => replaceBindings(tpe.widen)))
1978+
1979+ val typeBindingsTuple = tpd.tupleTypeTree(typeBindings.values.toList)
1980+
1981+ val replaceBindingsInTree = new TreeMap {
1982+ private [this ] var bindMap = Map .empty[Symbol , Symbol ]
1983+ override def transform (tree : tpd.Tree )(implicit ctx : Context ): tpd.Tree = {
1984+ tree match {
1985+ case tree : Bind =>
1986+ val sym = tree.symbol
1987+ val newInfo = replaceBindings(sym.info)
1988+ if (sym.info =:= newInfo) super .transform(tree)
1989+ else {
1990+ val newSym = ctx.newSymbol(sym.owner, sym.name, sym.flags, newInfo, sym.privateWithin, sym.coord)
1991+ bindMap += sym -> newSym
1992+ Bind (newSym, super .transform(tree.body))
1993+ }
1994+ case _ =>
1995+ val replaceBindingsInType = new ReplaceBindings {
1996+ override def apply (tp : Type ): Type = tp match {
1997+ case tp : TermRef => bindMap.get(tp.termSymbol).fold(tp)(_.typeRef)
1998+ case tp => super .apply(tp)
1999+ }
2000+ }
2001+ super .transform(tree).withType(replaceBindingsInType(tree.tpe))
2002+ }
2003+ }
2004+ }
2005+
2006+ val splicePat = typed(untpd.Tuple (splices.map(x => untpd.TypedSplice (replaceBindingsInTree.transform(x)))).withSpan(quoted.span), patType)
2007+
19702008 UnApply (
1971- fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToType( patType),
2009+ fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToTypeTrees(typeBindingsTuple :: TypeTree ( patType) :: Nil ),
19722010 implicits =
19732011 ref(defn.InternalQuoted_exprQuoteR ).appliedToType(shape.tpe).appliedTo(shape) ::
19742012 implicitArgTree(defn.TastyReflectionType , tree.span) :: Nil ,
@@ -1980,8 +2018,24 @@ class Typer extends Namer
19802018 }
19812019 }
19822020
1983- def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (Tree , List [Tree ]) = {
2021+ def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (Map [ Symbol , Bind ], Tree , List [Tree ]) = {
19842022 val ctx0 = ctx
2023+
2024+ val typeBindings : collection.mutable.Map [Symbol , Bind ] = collection.mutable.Map .empty
2025+ def getBinding (sym : Symbol ): Bind =
2026+ typeBindings.getOrElseUpdate(sym, {
2027+ val bindingBounds = TypeBounds .apply(defn.NothingType , defn.AnyType ) // TODO recover bounds
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+
19852039 object splitter extends tpd.TreeMap {
19862040 val patBuf = new mutable.ListBuffer [Tree ]
19872041 override def transform (tree : Tree )(implicit ctx : Context ) = tree match {
@@ -2014,17 +2068,28 @@ class Typer extends Namer
20142068 patBuf += Bind (sym, untpd.Ident (nme.WILDCARD ).withType(bindingExprTpe)).withSpan(ddef.span)
20152069 }
20162070 super .transform(tree)
2071+ case tdef : TypeDef if tdef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot ) =>
2072+ val bindingType = getBinding(tdef.symbol).symbol.typeRef
2073+ val bindingTypeTpe = AppliedType (defn.QuotedTypeType , bindingType :: Nil )
2074+ assert(tdef.name.startsWith(" $" ))
2075+ val bindName = tdef.name.toString.stripPrefix(" $" ).toTermName
2076+ val sym = ctx0.newPatternBoundSymbol(bindName, bindingTypeTpe, tdef.span)
2077+ patBuf += Bind (sym, untpd.Ident (nme.WILDCARD ).withType(bindingTypeTpe)).withSpan(tdef.span)
2078+ super .transform(tree)
20172079 case _ =>
20182080 super .transform(tree)
20192081 }
20202082 }
20212083 val result = splitter.transform(quoted)
2022- (result, splitter.patBuf.toList)
2084+ val patterns = splitter.patBuf.toList
2085+ (typeBindings.toMap, result, patterns)
20232086 }
20242087
20252088 /** A hole the shape pattern of a quoted.Matcher.unapply, representing a splice */
2026- def patternHole (splice : Tree )(implicit ctx : Context ): Tree =
2089+ def patternHole (splice : Tree )(implicit ctx : Context ): Tree = {
2090+ val Splice (pat) = splice
20272091 ref(defn.InternalQuoted_patternHoleR ).appliedToType(splice.tpe).withSpan(splice.span)
2092+ }
20282093
20292094 /** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */
20302095 def typedSplice (tree : untpd.Splice , pt : Type )(implicit ctx : Context ): Tree = track(" typedSplice" ) {
@@ -2063,14 +2128,47 @@ class Typer extends Namer
20632128
20642129 /** Translate ${ t: Type[T] }` into type `t.splice` while tracking the quotation level in the context */
20652130 def typedTypSplice (tree : untpd.TypSplice , pt : Type )(implicit ctx : Context ): Tree = track(" typedTypSplice" ) {
2131+ // TODO factor out comon code with typedSplice
20662132 ctx.compilationUnit.needsStaging = true
20672133 checkSpliceOutsideQuote(tree)
20682134 tree.expr match {
20692135 case untpd.Quote (innerType) if innerType.isType =>
20702136 ctx.warning(" Canceled quote directly inside a splice. ${ '[ XYZ ] } is equivalent to XYZ." , tree.sourcePos)
20712137 typed(innerType, pt)
20722138 case expr =>
2073- typedSelect(untpd.Select (tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span)
2139+ if (ctx.mode.is(Mode .QuotedPattern ) && level == 1 ) {
2140+ if (isFullyDefined(pt, ForceDegree .all)) {
2141+ // TODO is this error still relevant here? probably not
2142+ ctx.error(i " Type must be fully defined. \n Consider annotating the splice using a type ascription: \n ( $tree: XYZ). " , tree.expr.sourcePos)
2143+ tree.withType(UnspecifiedErrorType )
2144+ } else {
2145+ expr match {
2146+ case Ident (name) => typedIdent(untpd.Ident ((" $" + name).toTypeName), pt)
2147+ }
2148+
2149+ // println()
2150+ // println(expr)
2151+ // println()
2152+ // println()
2153+ // val bindingBounds = TypeBounds.apply(defn.NothingType, defn.AnyType)
2154+ // def getName(tree: untpd.Tree): TypeName = tree match {
2155+ // case tree: RefTree => ("$" + tree.name).toTypeName
2156+ // case tree: Typed => getName(tree.expr)
2157+ // }
2158+ // val sym = ctx.newPatternBoundSymbol(getName(expr), bindingBounds, expr.span)
2159+ // val bind = Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingBounds)).withSpan(expr.span)
2160+ //
2161+ // def spliceOwner(ctx: Context): Symbol =
2162+ // if (ctx.mode.is(Mode.QuotedPattern)) spliceOwner(ctx.outer) else ctx.owner
2163+ // val pat = typedPattern(tree.expr, defn.QuotedTypeType.appliedTo(sym.typeRef))(
2164+ // spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
2165+ // Splice(Typed(pat, AppliedTypeTree(TypeTree(defn.QuotedTypeType), bind :: Nil)))
2166+
2167+ }
2168+
2169+ } else {
2170+ typedSelect(untpd.Select (tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span)
2171+ }
20742172 }
20752173 }
20762174
0 commit comments