@@ -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) 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
@@ -128,29 +141,17 @@ trait QuotesAndSplices {
128141 */
129142 def typedAppliedSplice (tree : untpd.Apply , pt : Type )(using Context ): Tree = {
130143 assert(ctx.mode.is(Mode .QuotedPattern ))
131- val untpd .Apply (splice : untpd.Splice , args) = tree : @ unchecked
132- def isInBraces : Boolean = splice.span.end != splice.expr.span.end
133- if ! isFullyDefined(pt, ForceDegree .flipBottom) then
134- report.error(em " Type must be fully defined. " , splice.srcPos)
135- tree.withType(UnspecifiedErrorType )
136- else if isInBraces then // ${x}(...) match an application
144+ val untpd .Apply (splice : untpd.SplicePattern , args) = tree : @ unchecked
145+ def isInBraces : Boolean = splice.span.end != splice.body.span.end
146+ if isInBraces then // ${x}(...) match an application
137147 val typedArgs = args.map(arg => typedExpr(arg))
138148 val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
139- val splice1 = typedSplice (splice, defn.FunctionOf (argTypes, pt))
140- Apply (splice1.select(nme.apply), typedArgs).withType(pt).withSpan(tree.span )
149+ val splice1 = typedSplicePattern (splice, defn.FunctionOf (argTypes, pt))
150+ untpd.cpy. Apply (tree)( splice1.select(nme.apply), typedArgs).withType(pt)
141151 else // $x(...) higher-order quasipattern
142- val typedArgs = args.map {
143- case arg : untpd.Ident =>
144- typedExpr(arg)
145- case arg =>
146- report.error(" Open pattern expected an identifier" , arg.srcPos)
147- EmptyTree
148- }
149152 if args.isEmpty then
150- report.error(" Missing arguments for open pattern" , tree.srcPos)
151- val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
152- val typedPat = typedSplice(splice, defn.FunctionOf (argTypes, pt))
153- ref(defn.QuotedRuntimePatterns_patternHigherOrderHole ).appliedToType(pt).appliedTo(typedPat, SeqLiteral (typedArgs, TypeTree (defn.AnyType )))
153+ report.error(" Missing arguments for open pattern" , tree.srcPos)
154+ typedSplicePattern(untpd.cpy.SplicePattern (tree)(splice.body, args), pt)
154155 }
155156
156157 /** Type a pattern variable name `t` in quote pattern as `${given t$giveni: Type[t @ _]}`.
@@ -228,29 +229,16 @@ trait QuotesAndSplices {
228229 val freshTypeBindingsBuff = new mutable.ListBuffer [Tree ]
229230 val typePatBuf = new mutable.ListBuffer [Tree ]
230231 override def transform (tree : Tree )(using Context ) = tree match {
231- case Typed (splice : Splice , tpt) if ! tpt.tpe.derivesFrom(defn.RepeatedParamClass ) =>
232+ case Typed (splice @ SplicePattern (pat, Nil ) , tpt) if ! tpt.tpe.derivesFrom(defn.RepeatedParamClass ) =>
232233 transform(tpt) // Collect type bindings
233234 transform(splice)
234- case Apply (TypeApply (fn, targs), Splice (pat) :: args :: Nil ) if fn.symbol == defn.QuotedRuntimePatterns_patternHigherOrderHole =>
235- args match // TODO support these patterns. Possibly using scala.quoted.util.Var
236- case SeqLiteral (args, _) =>
237- for arg <- args; if arg.symbol.is(Mutable ) do
238- report.error(" References to `var`s cannot be used in higher-order pattern" , arg.srcPos)
239- try ref(defn.QuotedRuntimePatterns_higherOrderHole .termRef).appliedToTypeTrees(targs).appliedTo(args).withSpan(tree.span)
240- finally {
241- val patType = pat.tpe.widen
242- val patType1 = patType.translateFromRepeated(toArray = false )
243- val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
244- patBuf += pat1
245- }
246- case Splice (pat) =>
247- try ref(defn.QuotedRuntimePatterns_patternHole .termRef).appliedToType(tree.tpe).withSpan(tree.span)
248- finally {
249- val patType = pat.tpe.widen
250- val patType1 = patType.translateFromRepeated(toArray = false )
251- val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
252- patBuf += pat1
253- }
235+ case SplicePattern (pat, args) =>
236+ val patType = pat.tpe.widen
237+ val patType1 = patType.translateFromRepeated(toArray = false )
238+ val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
239+ patBuf += pat1
240+ if args.isEmpty then ref(defn.QuotedRuntimePatterns_patternHole .termRef).appliedToType(tree.tpe).withSpan(tree.span)
241+ else ref(defn.QuotedRuntimePatterns_higherOrderHole .termRef).appliedToType(tree.tpe).appliedTo(SeqLiteral (args, TypeTree (defn.AnyType ))).withSpan(tree.span)
254242 case Select (pat : Bind , _) if tree.symbol.isTypeSplice =>
255243 val sym = tree.tpe.dealias.typeSymbol
256244 if sym.exists then
0 commit comments