@@ -20,17 +20,18 @@ import dotty.tools.dotc.staging.StagingLevel.*
20
20
import dotty .tools .dotc .transform .SymUtils ._
21
21
import dotty .tools .dotc .typer .Implicits ._
22
22
import dotty .tools .dotc .typer .Inferencing ._
23
+ import dotty .tools .dotc .util .Property
23
24
import dotty .tools .dotc .util .Spans ._
24
25
import dotty .tools .dotc .util .Stats .record
25
26
import dotty .tools .dotc .reporting .IllegalVariableInPatternAlternative
26
27
import scala .collection .mutable
27
28
28
-
29
29
/** Type quotes `'{ ... }` and splices `${ ... }` */
30
30
trait QuotesAndSplices {
31
31
self : Typer =>
32
32
33
- import tpd ._
33
+ import tpd .*
34
+ import QuotesAndSplices .*
34
35
35
36
/** Translate `'{ e }` into `scala.quoted.Expr.apply(e)` and `'[T]` into `scala.quoted.Type.apply[T]`
36
37
* while tracking the quotation level in the context.
@@ -150,19 +151,26 @@ trait QuotesAndSplices {
150
151
* The resulting pattern is the split in `splitQuotePattern`.
151
152
*/
152
153
def typedQuotedTypeVar (tree : untpd.Ident , pt : Type )(using Context ): Tree =
153
- def spliceOwner (ctx : Context ): Symbol =
154
- if (ctx.mode.is(Mode .QuotedPattern )) spliceOwner(ctx.outer) else ctx.owner
155
- val name = tree.name.toTypeName
156
- val nameOfSyntheticGiven = PatMatGivenVarName .fresh(tree.name.toTermName)
157
- val expr = untpd.cpy.Ident (tree)(nameOfSyntheticGiven)
158
154
val typeSymInfo = pt match
159
155
case pt : TypeBounds => pt
160
156
case _ => TypeBounds .empty
161
- val typeSym = newSymbol(spliceOwner(ctx), name, EmptyFlags , typeSymInfo, NoSymbol , tree.span)
162
- typeSym.addAnnotation(Annotation (New (ref(defn.QuotedRuntimePatterns_patternTypeAnnot .typeRef)).withSpan(tree.span)))
163
- val pat = typedPattern(expr, defn.QuotedTypeClass .typeRef.appliedTo(typeSym.typeRef))(
164
- using spliceContext.retractMode(Mode .QuotedPattern ).withOwner(spliceOwner(ctx)))
165
- pat.select(tpnme.Underlying )
157
+ getQuotedPatternTypeVariable(tree.name.asTypeName) match
158
+ case Some (typeSym) =>
159
+ if ! (typeSymInfo =:= TypeBounds .empty) then
160
+ report.warning(em " Ignored bound $typeSymInfo\n\n Consider defining bounds explicitly `'{ $typeSym$typeSymInfo; ... }` " , tree.srcPos)
161
+ ref(typeSym)
162
+ case None =>
163
+ def spliceOwner (ctx : Context ): Symbol =
164
+ if (ctx.mode.is(Mode .QuotedPattern )) spliceOwner(ctx.outer) else ctx.owner
165
+ val name = tree.name.toTypeName
166
+ val nameOfSyntheticGiven = PatMatGivenVarName .fresh(tree.name.toTermName)
167
+ val expr = untpd.cpy.Ident (tree)(nameOfSyntheticGiven)
168
+ val typeSym = newSymbol(spliceOwner(ctx), name, EmptyFlags , typeSymInfo, NoSymbol , tree.span)
169
+ typeSym.addAnnotation(Annotation (New (ref(defn.QuotedRuntimePatterns_patternTypeAnnot .typeRef)).withSpan(tree.span)))
170
+ addQuotedPatternTypeVariable(typeSym)
171
+ val pat = typedPattern(expr, defn.QuotedTypeClass .typeRef.appliedTo(typeSym.typeRef))(
172
+ using spliceContext.retractMode(Mode .QuotedPattern ).withOwner(spliceOwner(ctx)))
173
+ pat.select(tpnme.Underlying )
166
174
167
175
def typedHole (tree : untpd.Hole , pt : Type )(using Context ): Tree =
168
176
val tpt = typedType(tree.tpt)
@@ -393,11 +401,24 @@ trait QuotesAndSplices {
393
401
case Some (argPt : ValueType ) => argPt // excludes TypeBounds
394
402
case _ => defn.AnyType
395
403
}
396
- val quoted0 = desugar.quotedPattern(quoted, untpd.TypedSplice (TypeTree (quotedPt)))
397
- val quoteCtx = quoteContext.addMode(Mode .QuotedPattern ).retractMode(Mode .Pattern )
398
- val quoted1 =
399
- if quoted.isType then typedType(quoted0, WildcardType )(using quoteCtx)
400
- else typedExpr(quoted0, WildcardType )(using quoteCtx)
404
+ val (untpdTypeVariables, quoted0) = desugar.quotedPatternTypeVariables(desugar.quotedPattern(quoted, untpd.TypedSplice (TypeTree (quotedPt))))
405
+
406
+ val (typeTypeVariables, patternCtx) =
407
+ val quoteCtx = quotePatternContext()
408
+ if untpdTypeVariables.isEmpty then (Nil , quoteCtx)
409
+ else typedBlockStats(untpdTypeVariables)(using quoteCtx)
410
+
411
+ val quoted1 = inContext(patternCtx) {
412
+ for typeVariable <- typeTypeVariables do
413
+ addQuotedPatternTypeVariable(typeVariable.symbol)
414
+
415
+ val pattern =
416
+ if quoted.isType then typedType(quoted0, WildcardType )
417
+ else typedExpr(quoted0, WildcardType )
418
+
419
+ if untpdTypeVariables.isEmpty then pattern
420
+ else tpd.Block (typeTypeVariables, pattern)
421
+ }
401
422
402
423
val (typeBindings, shape, splices) = splitQuotePattern(quoted1)
403
424
@@ -454,3 +475,24 @@ trait QuotesAndSplices {
454
475
proto = quoteClass.typeRef.appliedTo(replaceBindings(quoted1.tpe) & quotedPt))
455
476
}
456
477
}
478
+
479
+ object QuotesAndSplices {
480
+ import tpd ._
481
+
482
+ /** Key for mapping from quoted pattern type variable names into their symbol */
483
+ private val TypeVariableKey = new Property .Key [collection.mutable.Map [TypeName , Symbol ]]
484
+
485
+ /** Get the symbol for the quoted pattern type variable if it exists */
486
+ def getQuotedPatternTypeVariable (name : TypeName )(using Context ): Option [Symbol ] =
487
+ ctx.property(TypeVariableKey ).get.get(name)
488
+
489
+ /** Get the symbol for the quoted pattern type variable if it exists */
490
+ def addQuotedPatternTypeVariable (sym : Symbol )(using Context ): Unit =
491
+ ctx.property(TypeVariableKey ).get.update(sym.name.asTypeName, sym)
492
+
493
+ /** Context used to type the contents of a quoted */
494
+ def quotePatternContext ()(using Context ): Context =
495
+ quoteContext.fresh.setNewScope
496
+ .addMode(Mode .QuotedPattern ).retractMode(Mode .Pattern )
497
+ .setProperty(TypeVariableKey , collection.mutable.Map .empty)
498
+ }
0 commit comments