diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 479ae1fa9095..9c63452b1302 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1585,6 +1585,19 @@ object Parsers { t end typ + /** TypeBlock ::= {TypeBlockStat semi} Type + * TypeBlockStat ::= ‘type’ {nl} TypeDcl + */ + def typeBlock(): Tree = + val tDefs = new ListBuffer[Tree] + while in.token == TYPE do + val mods = defAnnotsMods(modifierTokens) + tDefs += typeDefOrDcl(in.offset, in.skipToken(mods)) + acceptStatSep() + val tpt = typ() + if tDefs.isEmpty then tpt else Block(tDefs.toList, tpt) + + private def makeKindProjectorTypeDef(name: TypeName): TypeDef = { val isVarianceAnnotated = name.startsWith("+") || name.startsWith("-") // We remove the variance marker from the name without passing along the specified variance at all @@ -2447,7 +2460,7 @@ object Parsers { atSpan(in.skipToken()) { withinStaged(StageKind.Quoted | (if (location.inPattern) StageKind.QuotedPattern else 0)) { Quote { - if (in.token == LBRACKET) inBrackets(typ()) + if (in.token == LBRACKET) inBrackets(typeBlock()) else stagedBlock() } } @@ -3080,8 +3093,8 @@ object Parsers { /* -------- PARAMETERS ------------------------------------------- */ /** DefParamClauses ::= DefParamClause { DefParamClause } -- and two DefTypeParamClause cannot be adjacent - * DefParamClause ::= DefTypeParamClause - * | DefTermParamClause + * DefParamClause ::= DefTypeParamClause + * | DefTermParamClause * | UsingParamClause */ def typeOrTermParamClauses( @@ -3179,7 +3192,7 @@ object Parsers { * UsingClsTermParamClause::= ‘(’ ‘using’ [‘erased’] (ClsParams | ContextTypes) ‘)’ * ClsParams ::= ClsParam {‘,’ ClsParam} * ClsParam ::= {Annotation} - * + * * TypelessClause ::= DefTermParamClause * | UsingParamClause * @@ -3557,13 +3570,13 @@ object Parsers { } } - + /** DefDef ::= DefSig [‘:’ Type] ‘=’ Expr * | this TypelessClauses [DefImplicitClause] `=' ConstrExpr * DefDcl ::= DefSig `:' Type * DefSig ::= id [DefTypeParamClause] DefTermParamClauses - * + * * if clauseInterleaving is enabled: * DefSig ::= id [DefParamClauses] [DefImplicitClause] */ @@ -3602,8 +3615,8 @@ object Parsers { val mods1 = addFlag(mods, Method) val ident = termIdent() var name = ident.name.asTermName - val paramss = - if in.featureEnabled(Feature.clauseInterleaving) then + val paramss = + if in.featureEnabled(Feature.clauseInterleaving) then // If you are making interleaving stable manually, please refer to the PR introducing it instead, section "How to make non-experimental" typeOrTermParamClauses(ParamOwner.Def, numLeadParams = numLeadParams) else @@ -3613,7 +3626,7 @@ object Parsers { joinParams(tparams, vparamss) var tpt = fromWithinReturnType { typedOpt() } - + if (migrateTo3) newLineOptWhenFollowedBy(LBRACE) val rhs = if in.token == EQUALS then diff --git a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala index 2fe5770c5b4b..846f4eb3e2dc 100644 --- a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala +++ b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala @@ -197,11 +197,11 @@ trait QuotesAndSplices { * ) * ``` */ - private def splitQuotePattern(quoted: Tree)(using Context): (Map[Symbol, Bind], Tree, List[Tree]) = { + private def splitQuotePattern(quoted: Tree)(using Context): (Map[Symbol, Tree], Tree, List[Tree]) = { val ctx0 = ctx - val typeBindings: collection.mutable.Map[Symbol, Bind] = collection.mutable.Map.empty - def getBinding(sym: Symbol): Bind = + val typeBindings: collection.mutable.Map[Symbol, Tree] = collection.mutable.Map.empty + def getBinding(sym: Symbol): Tree = typeBindings.getOrElseUpdate(sym, { val bindingBounds = sym.info val bsym = newPatternBoundSymbol(sym.name.toString.stripPrefix("$").toTypeName, bindingBounds, quoted.span) @@ -395,7 +395,10 @@ trait QuotesAndSplices { val quoted0 = desugar.quotedPattern(quoted, untpd.TypedSplice(TypeTree(quotedPt))) val quoteCtx = quoteContext.addMode(Mode.QuotedPattern).retractMode(Mode.Pattern) val quoted1 = - if quoted.isType then typedType(quoted0, WildcardType)(using quoteCtx) + if quoted.isType then typedType(quoted0, WildcardType)(using quoteCtx) match + case quoted1 @ Block(stats, Typed(tpt, _)) => cpy.Block(quoted1)(stats, tpt) + case quoted1 => quoted1 + else typedExpr(quoted0, WildcardType)(using quoteCtx) val (typeBindings, shape, splices) = splitQuotePattern(quoted1) diff --git a/docs/_docs/reference/syntax.md b/docs/_docs/reference/syntax.md index 8da41c7e6d0c..006cdb3e4b52 100644 --- a/docs/_docs/reference/syntax.md +++ b/docs/_docs/reference/syntax.md @@ -274,7 +274,7 @@ ColonArgument ::= colon [LambdaStart] LambdaStart ::= FunParams (‘=>’ | ‘?=>’) | HkTypeParamClause ‘=>’ Quoted ::= ‘'’ ‘{’ Block ‘}’ - | ‘'’ ‘[’ Type ‘]’ + | ‘'’ ‘[’ TypeBlock ‘]’ ExprSplice ::= spliceId -- if inside quoted block | ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern | ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted pattern @@ -293,6 +293,8 @@ BlockStat ::= Import | Extension | Expr1 | EndMarker +TypeBlock ::= {TypeBlockStat semi} Type +TypeBlockStat ::= ‘type’ {nl} TypeDcl ForExpr ::= ‘for’ ‘(’ Enumerators0 ‘)’ {nl} [‘do‘ | ‘yield’] Expr | ‘for’ ‘{’ Enumerators0 ‘}’ {nl} [‘do‘ | ‘yield’] Expr diff --git a/tests/pos-macros/i7264.scala b/tests/pos-macros/i7264.scala index c87409561bee..ff9fcece483f 100644 --- a/tests/pos-macros/i7264.scala +++ b/tests/pos-macros/i7264.scala @@ -3,5 +3,7 @@ class Foo { def f[T2](t: Type[T2])(using Quotes) = t match { case '[ *:[Int, t2] ] => Type.of[ *:[Int, t2] ] + case '[ type t <: Tuple; *:[Int, `t`] ] => + case '[ type t <: Tuple; *:[`t`, `t`] ] => } }