@@ -17,6 +17,7 @@ import dotty.tools.dotc.core.Types._
1717import dotty .tools .dotc .inlines .PrepareInlineable
1818import dotty .tools .dotc .staging .StagingLevel .*
1919import dotty .tools .dotc .transform .SymUtils ._
20+ import dotty .tools .dotc .typer .ErrorReporting .errorTree
2021import dotty .tools .dotc .typer .Implicits ._
2122import dotty .tools .dotc .typer .Inferencing ._
2223import dotty .tools .dotc .util .Spans ._
@@ -74,45 +75,55 @@ trait QuotesAndSplices {
7475 def typedSplice (tree : untpd.Splice , pt : Type )(using Context ): Tree = {
7576 record(" typedSplice" )
7677 checkSpliceOutsideQuote(tree)
78+ assert(! ctx.mode.is(Mode .QuotedPattern ))
7779 tree.expr match {
7880 case untpd.Quote (innerExpr, Nil ) if innerExpr.isTerm =>
7981 report.warning(" Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ." , tree.srcPos)
8082 return typed(innerExpr, pt)
8183 case _ =>
8284 }
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 )
96- }
97- 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
85+ if (level == 0 ) {
86+ // Mark the first inline method from the context as a macro
87+ def markAsMacro (c : Context ): Unit =
88+ if (c.owner eq c.outer.owner) markAsMacro(c.outer)
89+ else if (c.owner.isInlineMethod) c.owner.setFlag(Macro )
90+ else if (! c.outer.owner.is(Package )) markAsMacro(c.outer)
91+ else assert(ctx.reporter.hasErrors) // Did not find inline def to mark as macro
92+ markAsMacro(ctx)
11593 }
94+
95+ // TODO typecheck directly (without `exprSplice`)
96+ val internalSplice =
97+ untpd.Apply (untpd.ref(defn.QuotedRuntime_exprSplice .termRef), tree.expr)
98+ typedApply(internalSplice, pt)(using spliceContext).withSpan(tree.span) match
99+ case tree @ Apply (TypeApply (_, tpt :: Nil ), spliced :: Nil ) if tree.symbol == defn.QuotedRuntime_exprSplice =>
100+ cpy.Splice (tree)(spliced)
101+ case tree => tree
102+ }
103+
104+ def typedSplicePattern (tree : untpd.SplicePattern , pt : Type )(using Context ): Tree = {
105+ record(" typedSplicePattern" )
106+ if isFullyDefined(pt, ForceDegree .flipBottom) then
107+ def patternOuterContext (ctx : Context ): Context =
108+ if (ctx.mode.is(Mode .QuotedPattern )) patternOuterContext(ctx.outer) else ctx
109+ val typedArgs = tree.args.map {
110+ case arg : untpd.Ident =>
111+ typedExpr(arg)
112+ case arg =>
113+ report.error(" Open pattern expected an identifier" , arg.srcPos)
114+ EmptyTree
115+ }
116+ for arg <- typedArgs if arg.symbol.is(Mutable ) do // TODO support these patterns. Possibly using scala.quoted.util.Var
117+ report.error(" References to `var`s cannot be used in higher-order pattern" , arg.srcPos)
118+ val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
119+ val patType = if tree.args.isEmpty then pt else defn.FunctionOf (argTypes, pt)
120+ val pat = typedPattern(tree.body, defn.QuotedExprClass .typeRef.appliedTo(patType))(
121+ using spliceContext.retractMode(Mode .QuotedPattern ).addMode(Mode .Pattern ).withOwner(patternOuterContext(ctx).owner))
122+ val baseType = pat.tpe.baseType(defn.QuotedExprClass )
123+ val argType = if baseType.exists then baseType.argTypesHi.head else defn.NothingType
124+ untpd.cpy.SplicePattern (tree)(pat, typedArgs).withType(pt)
125+ else
126+ errorTree(tree, em " Type must be fully defined. \n Consider annotating the splice using a type ascription: \n ( $tree: XYZ). " , tree.body.srcPos)
116127 }
117128
118129 def typedHole (tree : untpd.Hole , pt : Type )(using Context ): Tree =
@@ -127,29 +138,17 @@ trait QuotesAndSplices {
127138 */
128139 def typedAppliedSplice (tree : untpd.Apply , pt : Type )(using Context ): Tree = {
129140 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
141+ val untpd .Apply (splice : untpd.SplicePattern , args) = tree : @ unchecked
142+ def isInBraces : Boolean = splice.span.end != splice.body.span.end
143+ if isInBraces then // ${x}(...) match an application
136144 val typedArgs = args.map(arg => typedExpr(arg))
137145 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 )
146+ val splice1 = typedSplicePattern (splice, defn.FunctionOf (argTypes, pt))
147+ untpd.cpy. Apply (tree)( splice1.select(nme.apply), typedArgs).withType(pt)
140148 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- }
148149 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 )))
150+ report.error(" Missing arguments for open pattern" , tree.srcPos)
151+ typedSplicePattern(untpd.cpy.SplicePattern (tree)(splice.body, args), pt)
153152 }
154153
155154 /** Type a pattern variable name `t` in quote pattern as `${given t$giveni: Type[t @ _]}`.
@@ -227,29 +226,16 @@ trait QuotesAndSplices {
227226 val freshTypeBindingsBuff = new mutable.ListBuffer [Tree ]
228227 val typePatBuf = new mutable.ListBuffer [Tree ]
229228 override def transform (tree : Tree )(using Context ) = tree match {
230- case Typed (splice : Splice , tpt) if ! tpt.tpe.derivesFrom(defn.RepeatedParamClass ) =>
229+ case Typed (splice @ SplicePattern (pat, Nil ) , tpt) if ! tpt.tpe.derivesFrom(defn.RepeatedParamClass ) =>
231230 transform(tpt) // Collect type bindings
232231 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- }
232+ case SplicePattern (pat, args) =>
233+ val patType = pat.tpe.widen
234+ val patType1 = patType.translateFromRepeated(toArray = false )
235+ val pat1 = if (patType eq patType1) pat else pat.withType(patType1)
236+ patBuf += pat1
237+ if args.isEmpty then ref(defn.QuotedRuntimePatterns_patternHole .termRef).appliedToType(tree.tpe).withSpan(tree.span)
238+ else ref(defn.QuotedRuntimePatterns_higherOrderHole .termRef).appliedToType(tree.tpe).appliedTo(SeqLiteral (args, TypeTree (defn.AnyType ))).withSpan(tree.span)
253239 case Select (pat : Bind , _) if tree.symbol.isTypeSplice =>
254240 val sym = tree.tpe.dealias.typeSymbol
255241 if sym.exists then
0 commit comments