@@ -110,8 +110,6 @@ trait QuotesAndSplices {
110110 def typedSplicePattern (tree : untpd.SplicePattern , pt : Type )(using Context ): Tree = {
111111 record(" typedSplicePattern" )
112112 if isFullyDefined(pt, ForceDegree .flipBottom) then
113- def patternOuterContext (ctx : Context ): Context =
114- if (ctx.mode.is(Mode .QuotedPattern )) patternOuterContext(ctx.outer) else ctx
115113 val typedArgs = withMode(Mode .InQuotePatternHoasArgs ) {
116114 tree.args.map {
117115 case arg : untpd.Ident =>
@@ -125,8 +123,7 @@ trait QuotesAndSplices {
125123 report.error(" References to `var`s cannot be used in higher-order pattern" , arg.srcPos)
126124 val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
127125 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)
130127 val baseType = pat.tpe.baseType(defn.QuotedExprClass )
131128 val argType = if baseType.exists then baseType.argTypesHi.head else defn.NothingType
132129 untpd.cpy.SplicePattern (tree)(pat, typedArgs).withType(pt)
@@ -166,14 +163,27 @@ trait QuotesAndSplices {
166163 val typeSymInfo = pt match
167164 case pt : TypeBounds => pt
168165 case _ => TypeBounds .empty
166+
167+ def warnOnInferredBounds (typeSym : Symbol ) =
168+ if ! (typeSymInfo =:= TypeBounds .empty) && ! (typeSym.info <:< typeSymInfo) then
169+ val (openQuote, closeQuote) = if isInQuotedExprPattern then (" '{" , " }" ) else (" '[" , " ]" )
170+ if isInQuotedTypePattern then // TODO remove this branch once SIP-53 is non-experimental
171+ report.warning(
172+ em """ Ignored bound $typeSymInfo
173+ |
174+ |This kind of pattern will be supported with SIP-53.
175+ |SIP-53: https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html
176+ | """ , tree.srcPos)
177+ else
178+ report.warning(em " Ignored bound $typeSymInfo\n\n Consider defining bounds explicitly: \n $openQuote $typeSym${typeSym.info & typeSymInfo}; ... $closeQuote" , tree.srcPos)
179+
169180 getQuotedPatternTypeVariable(tree.name.asTypeName) match
170181 case Some (typeSym) =>
171182 checkExperimentalFeature(
172183 " support for multiple references to the same type (without backticks) in quoted type patterns (SIP-53)" ,
173184 tree.srcPos,
174185 " \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)
186+ warnOnInferredBounds(typeSym)
177187 ref(typeSym)
178188 case None =>
179189 def spliceOwner (ctx : Context ): Symbol =
@@ -454,7 +464,7 @@ trait QuotesAndSplices {
454464 " \n\n SIP-53: https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html" )
455465
456466 val (typeTypeVariables, patternCtx) =
457- val quoteCtx = quotePatternContext()
467+ val quoteCtx = quotePatternContext(quoted.isType )
458468 if untpdTypeVariables.isEmpty then (Nil , quoteCtx)
459469 else typedBlockStats(untpdTypeVariables)(using quoteCtx)
460470
@@ -536,20 +546,49 @@ trait QuotesAndSplices {
536546object QuotesAndSplices {
537547 import tpd ._
538548
549+ private enum QuotePattenKind :
550+ case Expr , Type
551+
539552 /** Key for mapping from quoted pattern type variable names into their symbol */
540553 private val TypeVariableKey = new Property .Key [collection.mutable.Map [TypeName , Symbol ]]
541554
555+ /** Key that track in which kind of quote pattern we are */
556+ private val QuotePattenKindKey = new Property .Key [QuotePattenKind ]
557+
542558 /** Get the symbol for the quoted pattern type variable if it exists */
543559 def getQuotedPatternTypeVariable (name : TypeName )(using Context ): Option [Symbol ] =
544560 ctx.property(TypeVariableKey ).get.get(name)
545561
546- /** Get the symbol for the quoted pattern type variable if it exists */
562+ /** Get the symbol for the quoted pattern type variable if it exists */
547563 def addQuotedPatternTypeVariable (sym : Symbol )(using Context ): Unit =
548564 ctx.property(TypeVariableKey ).get.update(sym.name.asTypeName, sym)
549565
550- /** Context used to type the contents of a quoted */
551- def quotePatternContext ()(using Context ): Context =
566+ /** Is the current context in a quoted expression pattern?
567+ * But not in the splice of a quoted expression pattern.
568+ */
569+ def isInQuotedExprPattern (using Context ): Boolean =
570+ ctx.property(QuotePattenKindKey ).contains(QuotePattenKind .Expr )
571+
572+ /** Is the current context in a quoted type pattern?
573+ * But not in the splice of a quoted type pattern.
574+ */
575+ def isInQuotedTypePattern (using Context ): Boolean =
576+ ctx.property(QuotePattenKindKey ).contains(QuotePattenKind .Type )
577+
578+ /** Context used to type the contents of a quote pattern */
579+ def quotePatternContext (isTypePattern : Boolean )(using Context ): Context =
552580 quoteContext.fresh.setNewScope
553581 .addMode(Mode .QuotedPattern ).retractMode(Mode .Pattern )
582+ .addMode(Mode .QuotedPattern ).retractMode(Mode .Pattern ) // TODO do we need Mode.QuotedPattern?
554583 .setProperty(TypeVariableKey , collection.mutable.Map .empty)
584+ .setProperty(QuotePattenKindKey , if isTypePattern then QuotePattenKind .Type else QuotePattenKind .Expr )
585+
586+ /** Context used to type the contents of a quote pattern splice */
587+ def quotePatternSpliceContext (using Context ): Context =
588+ def patternOuterContext (ctx : Context ): Context =
589+ if ctx.mode.is(Mode .QuotedPattern ) then patternOuterContext(ctx.outer) else ctx
590+ spliceContext
591+ .retractMode(Mode .QuotedPattern ).addMode(Mode .Pattern )
592+ .dropProperty(QuotePattenKindKey )
593+ .withOwner(patternOuterContext(ctx).owner)
555594}
0 commit comments