@@ -17,6 +17,7 @@ import dotty.tools.dotc.core.Types._
17
17
import dotty .tools .dotc .inlines .PrepareInlineable
18
18
import dotty .tools .dotc .staging .StagingLevel .*
19
19
import dotty .tools .dotc .transform .SymUtils ._
20
+ import dotty .tools .dotc .typer .ErrorReporting .errorTree
20
21
import dotty .tools .dotc .typer .Implicits ._
21
22
import dotty .tools .dotc .typer .Inferencing ._
22
23
import dotty .tools .dotc .util .Spans ._
@@ -74,45 +75,55 @@ trait QuotesAndSplices {
74
75
def typedSplice (tree : untpd.Splice , pt : Type )(using Context ): Tree = {
75
76
record(" typedSplice" )
76
77
checkSpliceOutsideQuote(tree)
78
+ assert(! ctx.mode.is(Mode .QuotedPattern ))
77
79
tree.expr match {
78
80
case untpd.Quote (innerExpr, Nil ) if innerExpr.isTerm =>
79
81
report.warning(" Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ." , tree.srcPos)
80
82
return typed(innerExpr, pt)
81
83
case _ =>
82
84
}
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)
115
93
}
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)
116
127
}
117
128
118
129
def typedHole (tree : untpd.Hole , pt : Type )(using Context ): Tree =
@@ -127,29 +138,17 @@ trait QuotesAndSplices {
127
138
*/
128
139
def typedAppliedSplice (tree : untpd.Apply , pt : Type )(using Context ): Tree = {
129
140
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
136
144
val typedArgs = args.map(arg => typedExpr(arg))
137
145
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)
140
148
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
- }
148
149
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)
153
152
}
154
153
155
154
/** Type a pattern variable name `t` in quote pattern as `${given t$giveni: Type[t @ _]}`.
@@ -227,29 +226,16 @@ trait QuotesAndSplices {
227
226
val freshTypeBindingsBuff = new mutable.ListBuffer [Tree ]
228
227
val typePatBuf = new mutable.ListBuffer [Tree ]
229
228
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 ) =>
231
230
transform(tpt) // Collect type bindings
232
231
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)
253
239
case Select (pat : Bind , _) if tree.symbol.isTypeSplice =>
254
240
val sym = tree.tpe.dealias.typeSymbol
255
241
if sym.exists then
0 commit comments