@@ -1921,11 +1921,27 @@ class Typer extends Namer
1921
1921
val exprPt = pt.baseType(defn.QuotedExprClass )
1922
1922
val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType
1923
1923
val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode .QuotedPattern ))
1924
- val (shape, splices) = splitQuotePattern(quoted1)
1924
+ val (typeBindings, shape, splices) = splitQuotePattern(quoted1)
1925
+ // val typeBindings = splices.collect {
1926
+ // case t if t.tpe.derivesFrom(defn.QuotedTypeClass) =>
1927
+ // t.tpe.widen.argTypesHi.head.typeSymbol
1928
+ // }
1929
+ // val inQuoteTypeBinding = typeBindings.map { sym =>
1930
+ // ctx.newSymbol(sym.owner, (sym.name + "$$$").toTypeName, // TODO remove $$$, just there for debugging
1931
+ // EmptyFlags, sym.info, coord = sym.coord)
1932
+ // }
1933
+ // val shape2 =
1934
+ // seq(inQuoteTypeBinding.map(TypeDef), shape.subst(typeBindings, inQuoteTypeBinding))
1935
+
1936
+
1925
1937
val patType = defn.tupleType(splices.tpes.map(_.widen))
1938
+
1939
+ val typeBindingsTuple = tpd.tupleTypeTree(typeBindings)
1940
+
1926
1941
val splicePat = typed(untpd.Tuple (splices.map(untpd.TypedSplice (_))).withSpan(quoted.span), patType)
1942
+
1927
1943
UnApply (
1928
- fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToType( patType),
1944
+ fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToTypeTrees(typeBindingsTuple :: TypeTree ( patType) :: Nil ),
1929
1945
implicits =
1930
1946
ref(defn.InternalQuoted_exprQuoteR ).appliedToType(shape.tpe).appliedTo(shape) ::
1931
1947
implicitArgTree(defn.TastyReflectionType , tree.span) :: Nil ,
@@ -1937,8 +1953,24 @@ class Typer extends Namer
1937
1953
}
1938
1954
}
1939
1955
1940
- def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (Tree , List [Tree ]) = {
1956
+ def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (List [ Bind ], Tree , List [Tree ]) = {
1941
1957
val ctx0 = ctx
1958
+
1959
+ val typeBindings : collection.mutable.Map [Symbol , Bind ] = collection.mutable.Map .empty
1960
+ def getBinding (sym : Symbol ): Bind =
1961
+ typeBindings.getOrElseUpdate(sym, {
1962
+ val bindingBounds = TypeBounds .apply(defn.NothingType , defn.AnyType ) // TODO recover bounds
1963
+ val bsym = ctx.newPatternBoundSymbol((sym.name + " $" ).toTypeName, bindingBounds, quoted.span)
1964
+ Bind (bsym, untpd.Ident (nme.WILDCARD ).withType(bindingBounds)).withSpan(quoted.span)
1965
+ })
1966
+ def replaceTypeBindings = new TypeMap {
1967
+ def apply (tp : Type ): Type = tp match {
1968
+ case tp : TypeRef if tp.typeSymbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot ) =>
1969
+ getBinding(tp.typeSymbol).symbol.typeRef
1970
+ case _ => mapOver(tp)
1971
+ }
1972
+ }
1973
+
1942
1974
object splitter extends tpd.TreeMap {
1943
1975
val patBuf = new mutable.ListBuffer [Tree ]
1944
1976
override def transform (tree : Tree )(implicit ctx : Context ) = tree match {
@@ -1971,17 +2003,29 @@ class Typer extends Namer
1971
2003
patBuf += Bind (sym, untpd.Ident (nme.WILDCARD ).withType(bindingExprTpe)).withSpan(ddef.span)
1972
2004
}
1973
2005
super .transform(tree)
2006
+ case tdef : TypeDef if tdef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot ) =>
2007
+ val bindingType = getBinding(tdef.symbol).symbol.typeRef
2008
+ val bindingTypeTpe = AppliedType (defn.QuotedTypeType , bindingType :: Nil )
2009
+ assert(tdef.name.startsWith(" $" ))
2010
+ val bindName = tdef.name.toString.stripPrefix(" $" ).toTermName
2011
+ val sym = ctx0.newPatternBoundSymbol(bindName, bindingTypeTpe, tdef.span)
2012
+ patBuf += Bind (sym, untpd.Ident (nme.WILDCARD ).withType(bindingTypeTpe)).withSpan(tdef.span)
2013
+ super .transform(tree)
1974
2014
case _ =>
1975
2015
super .transform(tree)
1976
2016
}
1977
2017
}
1978
2018
val result = splitter.transform(quoted)
1979
- (result, splitter.patBuf.toList)
2019
+ val patterns = splitter.patBuf.toList
2020
+ (typeBindings.toList.map(_._2), result, patterns)
1980
2021
}
1981
2022
1982
2023
/** A hole the shape pattern of a quoted.Matcher.unapply, representing a splice */
1983
- def patternHole (splice : Tree )(implicit ctx : Context ): Tree =
1984
- ref(defn.InternalQuoted_patternHoleR ).appliedToType(splice.tpe).withSpan(splice.span)
2024
+ def patternHole (splice : Tree )(implicit ctx : Context ): Tree = {
2025
+ val Splice (pat) = splice
2026
+ if (pat.tpe.derivesFrom(defn.QuotedTypeClass )) AppliedTypeTree (ref(defn.InternalQuoted_patternTypeHole ), TypeTree (splice.tpe) :: Nil ).withSpan(splice.span)
2027
+ else ref(defn.InternalQuoted_patternHoleR ).appliedToType(splice.tpe).withSpan(splice.span)
2028
+ }
1985
2029
1986
2030
/** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */
1987
2031
def typedSplice (tree : untpd.Splice , pt : Type )(implicit ctx : Context ): Tree = track(" typedSplice" ) {
@@ -2020,9 +2064,48 @@ class Typer extends Namer
2020
2064
2021
2065
/** Translate ${ t: Type[T] }` into type `t.splice` while tracking the quotation level in the context */
2022
2066
def typedTypSplice (tree : untpd.TypSplice , pt : Type )(implicit ctx : Context ): Tree = track(" typedTypSplice" ) {
2067
+ // TODO factor out comon code with typedSplice
2023
2068
ctx.compilationUnit.needsStaging = true
2024
2069
checkSpliceOutsideQuote(tree)
2025
- typedSelect(untpd.Select (tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span)
2070
+ tree.expr match {
2071
+ case untpd.Quote (innerExpr) =>
2072
+ ctx.warning(" Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ." , tree.sourcePos)
2073
+ typed(innerExpr, pt)
2074
+ case expr =>
2075
+ if (ctx.mode.is(Mode .QuotedPattern ) && level == 1 ) {
2076
+ if (isFullyDefined(pt, ForceDegree .all)) {
2077
+ // TODO is this error still relevant here? probably not
2078
+ ctx.error(i " Type must be fully defined. \n Consider annotating the splice using a type ascription: \n ( $tree: XYZ). " , tree.expr.sourcePos)
2079
+ tree.withType(UnspecifiedErrorType )
2080
+ } else {
2081
+ expr match {
2082
+ case Ident (name) => typedIdent(untpd.Ident ((" $" + name).toTypeName), pt)
2083
+ }
2084
+
2085
+ // println()
2086
+ // println(expr)
2087
+ // println()
2088
+ // println()
2089
+ // val bindingBounds = TypeBounds.apply(defn.NothingType, defn.AnyType)
2090
+ // def getName(tree: untpd.Tree): TypeName = tree match {
2091
+ // case tree: RefTree => ("$" + tree.name).toTypeName
2092
+ // case tree: Typed => getName(tree.expr)
2093
+ // }
2094
+ // val sym = ctx.newPatternBoundSymbol(getName(expr), bindingBounds, expr.span)
2095
+ // val bind = Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingBounds)).withSpan(expr.span)
2096
+ //
2097
+ // def spliceOwner(ctx: Context): Symbol =
2098
+ // if (ctx.mode.is(Mode.QuotedPattern)) spliceOwner(ctx.outer) else ctx.owner
2099
+ // val pat = typedPattern(tree.expr, defn.QuotedTypeType.appliedTo(sym.typeRef))(
2100
+ // spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
2101
+ // Splice(Typed(pat, AppliedTypeTree(TypeTree(defn.QuotedTypeType), bind :: Nil)))
2102
+
2103
+ }
2104
+
2105
+ } else {
2106
+ typedSelect(untpd.Select (tree.expr, tpnme.splice), pt)(spliceContext).withSpan(tree.span)
2107
+ }
2108
+ }
2026
2109
}
2027
2110
2028
2111
private def checkSpliceOutsideQuote (tree : untpd.Tree )(implicit ctx : Context ): Unit = {
0 commit comments