@@ -78,7 +78,7 @@ trait QuotesAndSplices {
78
78
def typedSplice (tree : untpd.Splice , pt : Type )(using Context ): Tree = {
79
79
record(" typedSplice" )
80
80
checkSpliceOutsideQuote(tree)
81
- assert(! ctx.mode.is( Mode . QuotedPattern ) )
81
+ assert(! ctx.mode.isQuotedPattern )
82
82
tree.expr match {
83
83
case untpd.Quote (innerExpr, Nil ) if innerExpr.isTerm =>
84
84
report.warning(" Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ." , tree.srcPos)
@@ -110,8 +110,6 @@ trait QuotesAndSplices {
110
110
def typedSplicePattern (tree : untpd.SplicePattern , pt : Type )(using Context ): Tree = {
111
111
record(" typedSplicePattern" )
112
112
if isFullyDefined(pt, ForceDegree .flipBottom) then
113
- def patternOuterContext (ctx : Context ): Context =
114
- if (ctx.mode.is(Mode .QuotedPattern )) patternOuterContext(ctx.outer) else ctx
115
113
val typedArgs = withMode(Mode .InQuotePatternHoasArgs ) {
116
114
tree.args.map {
117
115
case arg : untpd.Ident =>
@@ -125,8 +123,7 @@ trait QuotesAndSplices {
125
123
report.error(" References to `var`s cannot be used in higher-order pattern" , arg.srcPos)
126
124
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
127
125
val patType = if tree.args.isEmpty then pt else defn.FunctionOf (argTypes, pt)
128
- val pat = typedPattern(tree.body, defn.QuotedExprClass .typeRef.appliedTo(patType))(
129
- using spliceContext.retractMode(Mode .QuotedPattern ).addMode(Mode .Pattern ).withOwner(patternOuterContext(ctx).owner))
126
+ val pat = typedPattern(tree.body, defn.QuotedExprClass .typeRef.appliedTo(patType))(using quotePatternSpliceContext)
130
127
val baseType = pat.tpe.baseType(defn.QuotedExprClass )
131
128
val argType = if baseType.exists then baseType.argTypesHi.head else defn.NothingType
132
129
untpd.cpy.SplicePattern (tree)(pat, typedArgs).withType(pt)
@@ -145,7 +142,7 @@ trait QuotesAndSplices {
145
142
* The prototype must be fully defined to be able to infer the type of `R`.
146
143
*/
147
144
def typedAppliedSplice (tree : untpd.Apply , pt : Type )(using Context ): Tree = {
148
- assert(ctx.mode.is( Mode . QuotedPattern ) )
145
+ assert(ctx.mode.isQuotedPattern )
149
146
val untpd .Apply (splice : untpd.SplicePattern , args) = tree : @ unchecked
150
147
def isInBraces : Boolean = splice.span.end != splice.body.span.end
151
148
if isInBraces then // ${x}(...) match an application
@@ -166,26 +163,29 @@ trait QuotesAndSplices {
166
163
val typeSymInfo = pt match
167
164
case pt : TypeBounds => pt
168
165
case _ => TypeBounds .empty
166
+
167
+ def warnOnInferredBounds (typeSym : Symbol ) =
168
+ if ! (typeSymInfo =:= TypeBounds .empty) && ! (typeSym.info <:< typeSymInfo) then
169
+ val (openQuote, closeQuote) = if ctx.mode.is(Mode .QuotedExprPattern ) then (" '{" , " }" ) else (" '[" , " ]" )
170
+ report.warning(em " Ignored bound $typeSymInfo\n\n Consider defining bounds explicitly: \n $openQuote $typeSym${typeSym.info & typeSymInfo}; ... $closeQuote" , tree.srcPos)
171
+
169
172
getQuotedPatternTypeVariable(tree.name.asTypeName) match
170
173
case Some (typeSym) =>
171
174
checkExperimentalFeature(
172
175
" support for multiple references to the same type (without backticks) in quoted type patterns (SIP-53)" ,
173
176
tree.srcPos,
174
177
" \n\n SIP-53: https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html" )
175
- if ! (typeSymInfo =:= TypeBounds .empty) && ! (typeSym.info <:< typeSymInfo) then
176
- report.warning(em " Ignored bound $typeSymInfo\n\n Consider defining bounds explicitly `'{ $typeSym${typeSym.info & typeSymInfo}; ... }` " , tree.srcPos)
178
+ warnOnInferredBounds(typeSym)
177
179
ref(typeSym)
178
180
case None =>
179
- def spliceOwner (ctx : Context ): Symbol =
180
- if (ctx.mode.is(Mode .QuotedPattern )) spliceOwner(ctx.outer) else ctx.owner
181
+ val spliceContext = quotePatternSpliceContext
181
182
val name = tree.name.toTypeName
182
183
val nameOfSyntheticGiven = PatMatGivenVarName .fresh(tree.name.toTermName)
183
184
val expr = untpd.cpy.Ident (tree)(nameOfSyntheticGiven)
184
- val typeSym = newSymbol(spliceOwner(ctx) , name, EmptyFlags , typeSymInfo, NoSymbol , tree.span)
185
+ val typeSym = newSymbol(spliceContext.owner , name, EmptyFlags , typeSymInfo, NoSymbol , tree.span)
185
186
typeSym.addAnnotation(Annotation (New (ref(defn.QuotedRuntimePatterns_patternTypeAnnot .typeRef)).withSpan(tree.span)))
186
187
addQuotedPatternTypeVariable(typeSym)
187
- val pat = typedPattern(expr, defn.QuotedTypeClass .typeRef.appliedTo(typeSym.typeRef))(
188
- using spliceContext.retractMode(Mode .QuotedPattern ).withOwner(spliceOwner(ctx)))
188
+ val pat = typedPattern(expr, defn.QuotedTypeClass .typeRef.appliedTo(typeSym.typeRef))(using spliceContext)
189
189
pat.select(tpnme.Underlying )
190
190
191
191
private def checkSpliceOutsideQuote (tree : untpd.Tree )(using Context ): Unit =
@@ -454,7 +454,7 @@ trait QuotesAndSplices {
454
454
" \n\n SIP-53: https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html" )
455
455
456
456
val (typeTypeVariables, patternCtx) =
457
- val quoteCtx = quotePatternContext()
457
+ val quoteCtx = quotePatternContext(quoted.isType )
458
458
if untpdTypeVariables.isEmpty then (Nil , quoteCtx)
459
459
else typedBlockStats(untpdTypeVariables)(using quoteCtx)
460
460
@@ -543,13 +543,26 @@ object QuotesAndSplices {
543
543
def getQuotedPatternTypeVariable (name : TypeName )(using Context ): Option [Symbol ] =
544
544
ctx.property(TypeVariableKey ).get.get(name)
545
545
546
- /** Get the symbol for the quoted pattern type variable if it exists */
546
+ /** Get the symbol for the quoted pattern type variable if it exists */
547
547
def addQuotedPatternTypeVariable (sym : Symbol )(using Context ): Unit =
548
548
ctx.property(TypeVariableKey ).get.update(sym.name.asTypeName, sym)
549
549
550
- /** Context used to type the contents of a quoted */
551
- def quotePatternContext ()(using Context ): Context =
550
+ /** Context used to type the contents of a quote pattern */
551
+ def quotePatternContext (isTypePattern : Boolean )(using Context ): Context =
552
552
quoteContext.fresh.setNewScope
553
- .addMode(Mode .QuotedPattern ).retractMode(Mode .Pattern )
553
+ .addMode(if isTypePattern then Mode .QuotedTypePattern else Mode .QuotedExprPattern )
554
+ .retractMode(Mode .Pattern ) // TODO do we need Mode.QuotedPattern?
554
555
.setProperty(TypeVariableKey , collection.mutable.Map .empty)
556
+
557
+ /** Context used to type the contents of a quote pattern splice */
558
+ def quotePatternSpliceContext (using Context ): Context =
559
+ spliceContext
560
+ .retractMode(Mode .QuotedPatternBits )
561
+ .addMode(Mode .Pattern )
562
+ .withOwner(quotePatternOwner(ctx))
563
+
564
+ /** First outer context owner that is outside of a quoted pattern context. */
565
+ private def quotePatternOwner (ctx : Context ): Symbol =
566
+ if ctx.mode.isQuotedPattern then quotePatternOwner(ctx.outer) else ctx.owner
567
+
555
568
}
0 commit comments