@@ -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 = tree.args.map {
116
114
case arg : untpd.Ident =>
117
115
typedExpr(arg)
@@ -124,7 +122,7 @@ trait QuotesAndSplices {
124
122
val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
125
123
val patType = if tree.args.isEmpty then pt else defn.FunctionOf (argTypes, pt)
126
124
val pat = typedPattern(tree.body, defn.QuotedExprClass .typeRef.appliedTo(patType))(
127
- using spliceContext.retractMode( Mode . QuotedPattern ).addMode( Mode . Pattern ).withOwner(patternOuterContext(ctx).owner) )
125
+ using quotePatternSpliceContext )
128
126
val baseType = pat.tpe.baseType(defn.QuotedExprClass )
129
127
val argType = if baseType.exists then baseType.argTypesHi.head else defn.NothingType
130
128
untpd.cpy.SplicePattern (tree)(pat, typedArgs).withType(pt)
@@ -164,22 +162,42 @@ trait QuotesAndSplices {
164
162
val typeSymInfo = pt match
165
163
case pt : TypeBounds => pt
166
164
case _ => TypeBounds .empty
165
+
166
+ def warnOnInferredBounds (typeSym : Symbol , ignoredBounds : Boolean ) =
167
+ if ! (typeSymInfo =:= TypeBounds .empty) then
168
+ val (openQuote, closeQuote) = if isInQuotedExprPattern then (" '{" , " }" ) else (" '[" , " ]" )
169
+ if ! ignoredBounds then
170
+ if ! isInQuotedTypePattern then // TODO remove this guard once SIP-53 is non-experimental
171
+ report.warning(em " Type variable ` $tree` has partially inferred bounds $typeSymInfo. \n\n Consider defining bounds explicitly: \n $openQuote $typeSym$typeSymInfo; ... $closeQuote" , tree.srcPos)
172
+ else if ! (typeSym.info <:< typeSymInfo) then
173
+ if isInQuotedTypePattern then // TODO remove this branch once SIP-53 is non-experimental
174
+ report.warning(
175
+ em """ Ignored bound $typeSymInfo
176
+ |
177
+ |This bound pattern is not supported yet.
178
+ |This kind of pattern will be supported with SIP-53.
179
+ |SIP-53: https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html
180
+ | """ , tree.srcPos)
181
+ else
182
+ report.warning(em " Ignored bound $typeSymInfo\n\n Consider defining bounds explicitly: \n $openQuote $typeSym${typeSym.info & typeSymInfo}; ... $closeQuote" , tree.srcPos)
183
+
167
184
getQuotedPatternTypeVariable(tree.name.asTypeName) match
168
185
case Some (typeSym) =>
169
186
checkExperimentalFeature(
170
187
" support for multiple references to the same type (without backticks) in quoted type patterns (SIP-53)" ,
171
188
tree.srcPos,
172
189
" \n\n SIP-53: https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html" )
173
- if ! (typeSymInfo =:= TypeBounds .empty) && ! (typeSym.info <:< typeSymInfo) then
174
- report.warning(em " Ignored bound $typeSymInfo\n\n Consider defining bounds explicitly `'{ $typeSym${typeSym.info & typeSymInfo}; ... }` " , tree.srcPos)
190
+ warnOnInferredBounds(typeSym, ignoredBounds = true )
175
191
ref(typeSym)
176
192
case None =>
193
+
177
194
def spliceOwner (ctx : Context ): Symbol =
178
195
if (ctx.mode.is(Mode .QuotedPattern )) spliceOwner(ctx.outer) else ctx.owner
179
196
val name = tree.name.toTypeName
180
197
val nameOfSyntheticGiven = PatMatGivenVarName .fresh(tree.name.toTermName)
181
198
val expr = untpd.cpy.Ident (tree)(nameOfSyntheticGiven)
182
199
val typeSym = newSymbol(spliceOwner(ctx), name, EmptyFlags , typeSymInfo, NoSymbol , tree.span)
200
+ warnOnInferredBounds(typeSym, ignoredBounds = false )
183
201
typeSym.addAnnotation(Annotation (New (ref(defn.QuotedRuntimePatterns_patternTypeAnnot .typeRef)).withSpan(tree.span)))
184
202
addQuotedPatternTypeVariable(typeSym)
185
203
val pat = typedPattern(expr, defn.QuotedTypeClass .typeRef.appliedTo(typeSym.typeRef))(
@@ -452,7 +470,7 @@ trait QuotesAndSplices {
452
470
" \n\n SIP-53: https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html" )
453
471
454
472
val (typeTypeVariables, patternCtx) =
455
- val quoteCtx = quotePatternContext()
473
+ val quoteCtx = quotePatternContext(quoted.isType )
456
474
if untpdTypeVariables.isEmpty then (Nil , quoteCtx)
457
475
else typedBlockStats(untpdTypeVariables)(using quoteCtx)
458
476
@@ -534,20 +552,40 @@ trait QuotesAndSplices {
534
552
object QuotesAndSplices {
535
553
import tpd ._
536
554
555
+ private enum QuotePattenKind :
556
+ case Expr , Type
557
+
537
558
/** Key for mapping from quoted pattern type variable names into their symbol */
538
559
private val TypeVariableKey = new Property .Key [collection.mutable.Map [TypeName , Symbol ]]
560
+ private val QuotePattenKindKey = new Property .Key [QuotePattenKind ]
539
561
540
562
/** Get the symbol for the quoted pattern type variable if it exists */
541
563
def getQuotedPatternTypeVariable (name : TypeName )(using Context ): Option [Symbol ] =
542
564
ctx.property(TypeVariableKey ).get.get(name)
543
565
544
- /** Get the symbol for the quoted pattern type variable if it exists */
566
+ def isInQuotedExprPattern (using Context ): Boolean =
567
+ ctx.property(QuotePattenKindKey ).contains(QuotePattenKind .Expr )
568
+
569
+ def isInQuotedTypePattern (using Context ): Boolean =
570
+ ctx.property(QuotePattenKindKey ).contains(QuotePattenKind .Type )
571
+
572
+ /** Get the symbol for the quoted pattern type variable if it exists */
545
573
def addQuotedPatternTypeVariable (sym : Symbol )(using Context ): Unit =
546
574
ctx.property(TypeVariableKey ).get.update(sym.name.asTypeName, sym)
547
575
548
- /** Context used to type the contents of a quoted */
549
- def quotePatternContext ()(using Context ): Context =
576
+ /** Context used to type the contents of a quote pattern */
577
+ def quotePatternContext (isTypePattern : Boolean )(using Context ): Context =
550
578
quoteContext.fresh.setNewScope
551
- .addMode(Mode .QuotedPattern ).retractMode(Mode .Pattern )
579
+ .addMode(Mode .QuotedPattern ).retractMode(Mode .Pattern ) // TODO do we need Mode.QuotedPattern?
552
580
.setProperty(TypeVariableKey , collection.mutable.Map .empty)
581
+ .setProperty(QuotePattenKindKey , if isTypePattern then QuotePattenKind .Type else QuotePattenKind .Expr )
582
+
583
+ /** Context used to type the contents of a quote pattern splice */
584
+ def quotePatternSpliceContext (using Context ): Context =
585
+ def patternOuterContext (ctx : Context ): Context =
586
+ if ctx.mode.is(Mode .QuotedPattern ) then patternOuterContext(ctx.outer) else ctx
587
+ spliceContext
588
+ .retractMode(Mode .QuotedPattern ).addMode(Mode .Pattern )
589
+ .dropProperty(QuotePattenKindKey )
590
+ .withOwner(patternOuterContext(ctx).owner)
553
591
}
0 commit comments