@@ -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 = tree.args.map {
116114 case arg : untpd.Ident =>
117115 typedExpr(arg)
@@ -124,7 +122,7 @@ trait QuotesAndSplices {
124122 val argTypes = typedArgs.map(_.tpe.widenTermRefExpr)
125123 val patType = if tree.args.isEmpty then pt else defn.FunctionOf (argTypes, pt)
126124 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 )
128126 val baseType = pat.tpe.baseType(defn.QuotedExprClass )
129127 val argType = if baseType.exists then baseType.argTypesHi.head else defn.NothingType
130128 untpd.cpy.SplicePattern (tree)(pat, typedArgs).withType(pt)
@@ -164,22 +162,42 @@ trait QuotesAndSplices {
164162 val typeSymInfo = pt match
165163 case pt : TypeBounds => pt
166164 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+
167184 getQuotedPatternTypeVariable(tree.name.asTypeName) match
168185 case Some (typeSym) =>
169186 checkExperimentalFeature(
170187 " support for multiple references to the same type (without backticks) in quoted type patterns (SIP-53)" ,
171188 tree.srcPos,
172189 " \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 )
175191 ref(typeSym)
176192 case None =>
193+
177194 def spliceOwner (ctx : Context ): Symbol =
178195 if (ctx.mode.is(Mode .QuotedPattern )) spliceOwner(ctx.outer) else ctx.owner
179196 val name = tree.name.toTypeName
180197 val nameOfSyntheticGiven = PatMatGivenVarName .fresh(tree.name.toTermName)
181198 val expr = untpd.cpy.Ident (tree)(nameOfSyntheticGiven)
182199 val typeSym = newSymbol(spliceOwner(ctx), name, EmptyFlags , typeSymInfo, NoSymbol , tree.span)
200+ warnOnInferredBounds(typeSym, ignoredBounds = false )
183201 typeSym.addAnnotation(Annotation (New (ref(defn.QuotedRuntimePatterns_patternTypeAnnot .typeRef)).withSpan(tree.span)))
184202 addQuotedPatternTypeVariable(typeSym)
185203 val pat = typedPattern(expr, defn.QuotedTypeClass .typeRef.appliedTo(typeSym.typeRef))(
@@ -452,7 +470,7 @@ trait QuotesAndSplices {
452470 " \n\n SIP-53: https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html" )
453471
454472 val (typeTypeVariables, patternCtx) =
455- val quoteCtx = quotePatternContext()
473+ val quoteCtx = quotePatternContext(quoted.isType )
456474 if untpdTypeVariables.isEmpty then (Nil , quoteCtx)
457475 else typedBlockStats(untpdTypeVariables)(using quoteCtx)
458476
@@ -534,20 +552,40 @@ trait QuotesAndSplices {
534552object QuotesAndSplices {
535553 import tpd ._
536554
555+ private enum QuotePattenKind :
556+ case Expr , Type
557+
537558 /** Key for mapping from quoted pattern type variable names into their symbol */
538559 private val TypeVariableKey = new Property .Key [collection.mutable.Map [TypeName , Symbol ]]
560+ private val QuotePattenKindKey = new Property .Key [QuotePattenKind ]
539561
540562 /** Get the symbol for the quoted pattern type variable if it exists */
541563 def getQuotedPatternTypeVariable (name : TypeName )(using Context ): Option [Symbol ] =
542564 ctx.property(TypeVariableKey ).get.get(name)
543565
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 */
545573 def addQuotedPatternTypeVariable (sym : Symbol )(using Context ): Unit =
546574 ctx.property(TypeVariableKey ).get.update(sym.name.asTypeName, sym)
547575
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 =
550578 quoteContext.fresh.setNewScope
551- .addMode(Mode .QuotedPattern ).retractMode(Mode .Pattern )
579+ .addMode(Mode .QuotedPattern ).retractMode(Mode .Pattern ) // TODO do we need Mode.QuotedPattern?
552580 .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)
553591}
0 commit comments