@@ -1967,65 +1967,132 @@ class Typer extends Namer
1967
1967
typedTypeApply(untpd.TypeApply (untpd.ref(defn.InternalQuoted_typeQuoteR ), quoted :: Nil ), pt)(quoteContext).withSpan(tree.span)
1968
1968
case quoted =>
1969
1969
ctx.compilationUnit.needsStaging = true
1970
- if (ctx.mode.is(Mode .Pattern ) && level == 0 ) {
1971
- val exprPt = pt.baseType(defn.QuotedExprClass )
1972
- val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType
1973
- val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode .QuotedPattern ))
1974
-
1975
- val (typeBindings, shape, splices) = splitQuotePattern(quoted1)
1976
-
1977
- class ReplaceBindings extends TypeMap () {
1978
- override def apply (tp : Type ): Type = tp match {
1979
- case tp : TypeRef =>
1980
- val tp1 = if (tp.typeSymbol == defn.QuotedType_splice ) tp.dealias else tp
1981
- typeBindings.get(tp1.typeSymbol).fold(tp)(_.symbol.typeRef)
1982
- case tp => mapOver(tp)
1983
- }
1984
- }
1985
- val replaceBindings = new ReplaceBindings
1986
- val patType = defn.tupleType(splices.tpes.map(tpe => replaceBindings(tpe.widen)))
1987
-
1988
- val typeBindingsTuple = tpd.tupleTypeTree(typeBindings.values.toList)
1989
-
1990
- val replaceBindingsInTree = new TreeMap {
1991
- private [this ] var bindMap = Map .empty[Symbol , Symbol ]
1992
- override def transform (tree : tpd.Tree )(implicit ctx : Context ): tpd.Tree = {
1993
- tree match {
1994
- case tree : Bind =>
1995
- val sym = tree.symbol
1996
- val newInfo = replaceBindings(sym.info)
1997
- val newSym = ctx.newSymbol(sym.owner, sym.name, sym.flags, newInfo, sym.privateWithin, sym.coord)
1998
- bindMap += sym -> newSym
1999
- Bind (newSym, transform(tree.body)).withSpan(sym.span)
2000
- case _ =>
2001
- super .transform(tree).withType(replaceBindingsInType(tree.tpe))
2002
- }
2003
- }
2004
- private [this ] val replaceBindingsInType = new ReplaceBindings {
2005
- override def apply (tp : Type ): Type = tp match {
2006
- case tp : TermRef => bindMap.get(tp.termSymbol).fold[Type ](tp)(_.typeRef)
2007
- case tp => super .apply(tp)
2008
- }
2009
- }
2010
- }
2011
-
2012
- val splicePat = typed(untpd.Tuple (splices.map(x => untpd.TypedSplice (replaceBindingsInTree.transform(x)))).withSpan(quoted.span), patType)
2013
-
2014
- UnApply (
2015
- fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToTypeTrees(typeBindingsTuple :: TypeTree (patType) :: Nil ),
2016
- implicits =
2017
- ref(defn.InternalQuoted_exprQuoteR ).appliedToType(shape.tpe).appliedTo(shape) ::
2018
- Literal (Constant (typeBindings.nonEmpty)) ::
2019
- implicitArgTree(defn.QuoteContextType , tree.span) :: Nil ,
2020
- patterns = splicePat :: Nil ,
2021
- proto = pt)
2022
- }
1970
+ if (ctx.mode.is(Mode .Pattern ) && level == 0 )
1971
+ typedQuotePattern(quoted, pt, tree.span)
2023
1972
else
2024
1973
typedApply(untpd.Apply (untpd.ref(defn.InternalQuoted_exprQuoteR ), quoted), pt)(quoteContext).withSpan(tree.span)
2025
1974
}
2026
1975
}
2027
1976
2028
- def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (Map [Symbol , Bind ], Tree , List [Tree ]) = {
1977
+ /** Type a quote pattern `case '{ <quoted> } =>` qiven the a current prototype. Typing the pattern
1978
+ * will also transform it into a call to `scala.internal.quoted.Matcher.unapply`.
1979
+ *
1980
+ * Code directly inside the quote is typed as an expression using Mode.QuotedPattern. Splices
1981
+ * within the quotes become patterns again and typed acordingly.
1982
+ *
1983
+ * ```
1984
+ * case '{ ($ls: List[$t]) } =>
1985
+ * // `t` is of type `Type[T$1]` for some unknown T$1
1986
+ * // `t` is implicitly available
1987
+ * // `l` is of type `Expr[List[T$1]]`
1988
+ * '{ val h: $t = $ls.head }
1989
+ * ```
1990
+ *
1991
+ * For each type splice we will create a new type binding in the pattern match ($t @ _ in this case)
1992
+ * and a corresponding type in the quoted pattern as a hole (@patternBindHole type $t in this case).
1993
+ * All these generated types are inserted at the start of the quoted code.
1994
+ *
1995
+ * After typing the tree will resemble
1996
+ *
1997
+ * ```
1998
+ * case '{ type ${given t: Type[$t @ _]}; ${ls: Expr[List[$t]]} } => ...
1999
+ * ```
2000
+ *
2001
+ * Then the pattern is _split_ into the expression containd in the pattern replacing the splices by holes,
2002
+ * and the patterns in the splices. All these are recombined into a call to `Matcher.unapply`.
2003
+ *
2004
+ * ```
2005
+ * case scala.internal.quoted.Matcher.unapply[
2006
+ * Tuple1[$t @ _], // Type binging definition
2007
+ * Tuple2[Type[$t], Expr[List[$t]]] // Typing the result of the pattern match
2008
+ * ](
2009
+ * Tuple2.unapply
2010
+ * [Type[$t], Expr[List[$t]]] //Propagated from the tuple above
2011
+ * (implict t @ _, ls @ _: Expr[List[$t]]) // from the spliced patterns
2012
+ * )(
2013
+ * '{ // Runtime quote Matcher.unapply uses to mach against. Expression directly inside the quoted pattern without the splices
2014
+ * @scala.internal.Quoted.patternBindHole type $t
2015
+ * scala.internal.Quoted.patternHole[List[$t]]
2016
+ * },
2017
+ * true, // If there is at least one type splice. Used to instantiate the context with or without GADT constraints
2018
+ * x$2 // tasty.Reflection instance
2019
+ * ) => ...
2020
+ * ```
2021
+ */
2022
+ private def typedQuotePattern (quoted : untpd.Tree , pt : Type , quoteSpan : Span )(implicit ctx : Context ): Tree = {
2023
+ val exprPt = pt.baseType(defn.QuotedExprClass )
2024
+ val quotedPt = if (exprPt.exists) exprPt.argTypesHi.head else defn.AnyType
2025
+ val quoted1 = typedExpr(quoted, quotedPt)(quoteContext.addMode(Mode .QuotedPattern ))
2026
+
2027
+ val (typeBindings, shape, splices) = splitQuotePattern(quoted1)
2028
+
2029
+ class ReplaceBindings extends TypeMap () {
2030
+ override def apply (tp : Type ): Type = tp match {
2031
+ case tp : TypeRef =>
2032
+ val tp1 = if (tp.typeSymbol == defn.QuotedType_splice ) tp.dealias else tp
2033
+ typeBindings.get(tp1.typeSymbol).fold(tp)(_.symbol.typeRef)
2034
+ case tp => mapOver(tp)
2035
+ }
2036
+ }
2037
+ val replaceBindings = new ReplaceBindings
2038
+ val patType = defn.tupleType(splices.tpes.map(tpe => replaceBindings(tpe.widen)))
2039
+
2040
+ val typeBindingsTuple = tpd.tupleTypeTree(typeBindings.values.toList)
2041
+
2042
+ val replaceBindingsInTree = new TreeMap {
2043
+ private [this ] var bindMap = Map .empty[Symbol , Symbol ]
2044
+ override def transform (tree : tpd.Tree )(implicit ctx : Context ): tpd.Tree = {
2045
+ tree match {
2046
+ case tree : Bind =>
2047
+ val sym = tree.symbol
2048
+ val newInfo = replaceBindings(sym.info)
2049
+ val newSym = ctx.newSymbol(sym.owner, sym.name, sym.flags, newInfo, sym.privateWithin, sym.coord)
2050
+ bindMap += sym -> newSym
2051
+ Bind (newSym, transform(tree.body)).withSpan(sym.span)
2052
+ case _ =>
2053
+ super .transform(tree).withType(replaceBindingsInType(tree.tpe))
2054
+ }
2055
+ }
2056
+ private [this ] val replaceBindingsInType = new ReplaceBindings {
2057
+ override def apply (tp : Type ): Type = tp match {
2058
+ case tp : TermRef => bindMap.get(tp.termSymbol).fold[Type ](tp)(_.typeRef)
2059
+ case tp => super .apply(tp)
2060
+ }
2061
+ }
2062
+ }
2063
+
2064
+ val splicePat = typed(untpd.Tuple (splices.map(x => untpd.TypedSplice (replaceBindingsInTree.transform(x)))).withSpan(quoted.span), patType)
2065
+
2066
+ UnApply (
2067
+ fun = ref(defn.InternalQuotedMatcher_unapplyR ).appliedToTypeTrees(typeBindingsTuple :: TypeTree (patType) :: Nil ),
2068
+ implicits =
2069
+ ref(defn.InternalQuoted_exprQuoteR ).appliedToType(shape.tpe).appliedTo(shape) ::
2070
+ Literal (Constant (typeBindings.nonEmpty)) ::
2071
+ implicitArgTree(defn.QuoteContextType , quoteSpan) :: Nil ,
2072
+ patterns = splicePat :: Nil ,
2073
+ proto = pt)
2074
+ }
2075
+
2076
+ /** Split a typed quoted pattern is split into its type bindings, pattern expression and inner patterns.
2077
+ * Type definitions with `@patternBindHole` will be inserted in the pattern expression for each type binding.
2078
+ *
2079
+ * A quote pattern
2080
+ * ```
2081
+ * case '{ type ${given t: Type[$t @ _]}; ${ls: Expr[List[$t]]} } => ...
2082
+ * ```
2083
+ * will return
2084
+ * ```
2085
+ * (
2086
+ * Map(<$t>: Symbol -> <$t @ _>: Bind),
2087
+ * <'{
2088
+ * @scala.internal.Quoted.patternBindHole type $t
2089
+ * scala.internal.Quoted.patternHole[List[$t]]
2090
+ * }>: Tree,
2091
+ * List(<ls: Expr[List[$t]]>: Tree)
2092
+ * )
2093
+ * ```
2094
+ */
2095
+ private def splitQuotePattern (quoted : Tree )(implicit ctx : Context ): (Map [Symbol , Bind ], Tree , List [Tree ]) = {
2029
2096
val ctx0 = ctx
2030
2097
2031
2098
val typeBindings : collection.mutable.Map [Symbol , Bind ] = collection.mutable.Map .empty
@@ -2047,7 +2114,7 @@ class Typer extends Namer
2047
2114
val exprTpt = AppliedTypeTree (TypeTree (defn.QuotedExprType ), tpt1 :: Nil )
2048
2115
transform(Splice (Typed (pat, exprTpt)))
2049
2116
case Splice (pat) =>
2050
- try patternHole( tree)
2117
+ try ref(defn. InternalQuoted_patternHoleR ).appliedToType( tree.tpe).withSpan(tree.span )
2051
2118
finally {
2052
2119
val patType = pat.tpe.widen
2053
2120
val patType1 = patType.underlyingIfRepeated(isJava = false )
@@ -2122,12 +2189,6 @@ class Typer extends Namer
2122
2189
(typeBindings.toMap, shape2, patterns)
2123
2190
}
2124
2191
2125
- /** A hole the shape pattern of a quoted.Matcher.unapply, representing a splice */
2126
- def patternHole (splice : Tree )(implicit ctx : Context ): Tree = {
2127
- val Splice (pat) = splice
2128
- ref(defn.InternalQuoted_patternHoleR ).appliedToType(splice.tpe).withSpan(splice.span)
2129
- }
2130
-
2131
2192
/** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */
2132
2193
def typedSplice (tree : untpd.Splice , pt : Type )(implicit ctx : Context ): Tree = track(" typedSplice" ) {
2133
2194
checkSpliceOutsideQuote(tree)
0 commit comments