@@ -74,44 +74,57 @@ trait QuotesAndSplices {
7474 def typedSplice (tree : untpd.Splice , pt : Type )(using Context ): Tree = {
7575 record(" typedSplice" )
7676 checkSpliceOutsideQuote(tree)
77+ assert(! ctx.mode.is(Mode .QuotedPattern ))
7778 tree.expr match {
7879 case untpd.Quote (innerExpr, Nil ) if innerExpr.isTerm =>
7980 report.warning(" Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ." , tree.srcPos)
8081 return typed(innerExpr, pt)
8182 case _ =>
8283 }
83- if (ctx.mode.is(Mode .QuotedPattern ))
84- if (isFullyDefined(pt, ForceDegree .flipBottom)) {
85- def spliceOwner (ctx : Context ): Symbol =
86- if (ctx.mode.is(Mode .QuotedPattern )) spliceOwner(ctx.outer) else ctx.owner
87- val pat = typedPattern(tree.expr, defn.QuotedExprClass .typeRef.appliedTo(pt))(
88- using spliceContext.retractMode(Mode .QuotedPattern ).addMode(Mode .Pattern ).withOwner(spliceOwner(ctx)))
89- val baseType = pat.tpe.baseType(defn.QuotedExprClass )
90- val argType = if baseType != NoType then baseType.argTypesHi.head else defn.NothingType
91- Splice (pat, argType).withSpan(tree.span)
92- }
93- else {
94- report.error(em " Type must be fully defined. \n Consider annotating the splice using a type ascription: \n ( $tree: XYZ). " , tree.expr.srcPos)
95- tree.withType(UnspecifiedErrorType )
84+ if (level == 0 ) {
85+ // Mark the first inline method from the context as a macro
86+ def markAsMacro (c : Context ): Unit =
87+ if (c.owner eq c.outer.owner) markAsMacro(c.outer)
88+ else if (c.owner.isInlineMethod) c.owner.setFlag(Macro )
89+ else if (! c.outer.owner.is(Package )) markAsMacro(c.outer)
90+ else assert(ctx.reporter.hasErrors) // Did not find inline def to mark as macro
91+ markAsMacro(ctx)
92+ }
93+
94+ // TODO typecheck directly (without `exprSplice`)
95+ val internalSplice =
96+ untpd.Apply (untpd.ref(defn.QuotedRuntime_exprSplice .termRef), tree.expr)
97+ typedApply(internalSplice, pt)(using spliceContext).withSpan(tree.span) match
98+ case tree @ Apply (TypeApply (_, tpt :: Nil ), spliced :: Nil ) if tree.symbol == defn.QuotedRuntime_exprSplice =>
99+ cpy.Splice (tree)(spliced)
100+ case tree => tree
101+ }
102+
103+ def typedSplicePattern (tree : untpd.SplicePattern , pt : Type )(using Context ): Tree = {
104+ record(" typedSplicePattern" )
105+ if (isFullyDefined(pt, ForceDegree .flipBottom)) {
106+ def spliceOwner (ctx : Context ): Symbol =
107+ if (ctx.mode.is(Mode .QuotedPattern )) spliceOwner(ctx.outer) else ctx.owner
108+ val typedArgs = tree.args.map {
109+ case arg : untpd.Ident =>
110+ typedExpr(arg)
111+ case arg =>
112+ report.error(" Open pattern expected an identifier" , arg.srcPos)
113+ EmptyTree
96114 }
115+ for arg <- typedArgs if arg.symbol.is(Mutable ) do // TODO support these patterns. Possibly using scala.quoted.util.Var
116+ report.error(" References to `var`s cannot be used in higher-order pattern" , arg.srcPos)
117+ val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
118+ val patType = if tree.args.isEmpty then pt else defn.FunctionOf (argTypes, pt)
119+ val pat = typedPattern(tree.body, defn.QuotedExprClass .typeRef.appliedTo(patType))(
120+ using spliceContext.retractMode(Mode .QuotedPattern ).addMode(Mode .Pattern ).withOwner(spliceOwner(ctx)))
121+ val baseType = pat.tpe.baseType(defn.QuotedExprClass )
122+ val argType = if baseType != NoType then baseType.argTypesHi.head else defn.NothingType
123+ untpd.cpy.SplicePattern (tree)(pat, typedArgs).withType(pt)
124+ }
97125 else {
98- if (level == 0 ) {
99- // Mark the first inline method from the context as a macro
100- def markAsMacro (c : Context ): Unit =
101- if (c.owner eq c.outer.owner) markAsMacro(c.outer)
102- else if (c.owner.isInlineMethod) c.owner.setFlag(Macro )
103- else if (! c.outer.owner.is(Package )) markAsMacro(c.outer)
104- else assert(ctx.reporter.hasErrors) // Did not find inline def to mark as macro
105- markAsMacro(ctx)
106- }
107-
108- // TODO typecheck directly (without `exprSplice`)
109- val internalSplice =
110- untpd.Apply (untpd.ref(defn.QuotedRuntime_exprSplice .termRef), tree.expr)
111- typedApply(internalSplice, pt)(using spliceContext).withSpan(tree.span) match
112- case tree @ Apply (TypeApply (_, tpt :: Nil ), spliced :: Nil ) if tree.symbol == defn.QuotedRuntime_exprSplice =>
113- cpy.Splice (tree)(spliced)
114- case tree => tree
126+ report.error(em " Type must be fully defined. \n Consider annotating the splice using a type ascription: \n ( $tree: XYZ). " , tree.body.srcPos)
127+ tree.withType(UnspecifiedErrorType )
115128 }
116129 }
117130
@@ -127,29 +140,17 @@ trait QuotesAndSplices {
127140 */
128141 def typedAppliedSplice (tree : untpd.Apply , pt : Type )(using Context ): Tree = {
129142 assert(ctx.mode.is(Mode .QuotedPattern ))
130- val untpd .Apply (splice : untpd.Splice , args) = tree : @ unchecked
131- def isInBraces : Boolean = splice.span.end != splice.expr.span.end
132- if ! isFullyDefined(pt, ForceDegree .flipBottom) then
133- report.error(em " Type must be fully defined. " , splice.srcPos)
134- tree.withType(UnspecifiedErrorType )
135- else if isInBraces then // ${x}(...) match an application
143+ val untpd .Apply (splice : untpd.SplicePattern , args) = tree : @ unchecked
144+ def isInBraces : Boolean = splice.span.end != splice.body.span.end
145+ if isInBraces then // ${x}(...) match an application
136146 val typedArgs = args.map(arg => typedExpr(arg))
137147 val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
138- val splice1 = typedSplice (splice, defn.FunctionOf (argTypes, pt))
139- Apply (splice1.select(nme.apply), typedArgs).withType(pt).withSpan(tree.span )
148+ val splice1 = typedSplicePattern (splice, defn.FunctionOf (argTypes, pt))
149+ untpd.cpy. Apply (tree)( splice1.select(nme.apply), typedArgs).withType(pt)
140150 else // $x(...) higher-order quasipattern
141- val typedArgs = args.map {
142- case arg : untpd.Ident =>
143- typedExpr(arg)
144- case arg =>
145- report.error(" Open pattern expected an identifier" , arg.srcPos)
146- EmptyTree
147- }
148151 if args.isEmpty then
149- report.error(" Missing arguments for open pattern" , tree.srcPos)
150- val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
151- val typedPat = typedSplice(splice, defn.FunctionOf (argTypes, pt))
152- ref(defn.QuotedRuntimePatterns_patternHigherOrderHole ).appliedToType(pt).appliedTo(typedPat, SeqLiteral (typedArgs, TypeTree (defn.AnyType )))
152+ report.error(" Missing arguments for open pattern" , tree.srcPos)
153+ typedSplicePattern(untpd.cpy.SplicePattern (tree)(splice.body, args), pt)
153154 }
154155
155156 /** Type a pattern variable name `t` in quote pattern as `${given t$giveni: Type[t @ _]}`.
@@ -227,29 +228,16 @@ trait QuotesAndSplices {
227228 val freshTypeBindingsBuff = new mutable.ListBuffer [Tree ]
228229 val typePatBuf = new mutable.ListBuffer [Tree ]
229230 override def transform (tree : Tree )(using Context ) = tree match {
230- case Typed (splice : Splice , tpt) if ! tpt.tpe.derivesFrom(defn.RepeatedParamClass ) =>
231+ case Typed (splice @ SplicePattern (pat, Nil ) , tpt) if ! tpt.tpe.derivesFrom(defn.RepeatedParamClass ) =>
231232 transform(tpt) // Collect type bindings
232233 transform(splice)
233- case Apply (TypeApply (fn, targs), Splice (pat) :: args :: Nil ) if fn.symbol == defn.QuotedRuntimePatterns_patternHigherOrderHole =>
234- args match // TODO support these patterns. Possibly using scala.quoted.util.Var
235- case SeqLiteral (args, _) =>
236- for arg <- args; if arg.symbol.is(Mutable ) do
237- report.error(" References to `var`s cannot be used in higher-order pattern" , arg.srcPos)
238- try ref(defn.QuotedRuntimePatterns_higherOrderHole .termRef).appliedToTypeTrees(targs).appliedTo(args).withSpan(tree.span)
239- finally {
240- val patType = pat.tpe.widen
241- val patType1 = patType.translateFromRepeated(toArray = false )
242- val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
243- patBuf += pat1
244- }
245- case Splice (pat) =>
246- try ref(defn.QuotedRuntimePatterns_patternHole .termRef).appliedToType(tree.tpe).withSpan(tree.span)
247- finally {
248- val patType = pat.tpe.widen
249- val patType1 = patType.translateFromRepeated(toArray = false )
250- val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
251- patBuf += pat1
252- }
234+ case SplicePattern (pat, args) =>
235+ val patType = pat.tpe.widen
236+ val patType1 = patType.translateFromRepeated(toArray = false )
237+ val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
238+ patBuf += pat1
239+ if args.isEmpty then ref(defn.QuotedRuntimePatterns_patternHole .termRef).appliedToType(tree.tpe).withSpan(tree.span)
240+ else ref(defn.QuotedRuntimePatterns_higherOrderHole .termRef).appliedToType(tree.tpe).appliedTo(SeqLiteral (args, TypeTree (defn.AnyType ))).withSpan(tree.span)
253241 case Select (pat : Bind , _) if tree.symbol.isTypeSplice =>
254242 val sym = tree.tpe.dealias.typeSymbol
255243 if sym.exists then
0 commit comments