Skip to content

Support type variable definitions in quoted patterns #16942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
}
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -3179,7 +3192,7 @@ object Parsers {
* UsingClsTermParamClause::= ‘(’ ‘using’ [‘erased’] (ClsParams | ContextTypes) ‘)’
* ClsParams ::= ClsParam {‘,’ ClsParam}
* ClsParam ::= {Annotation}
*
*
* TypelessClause ::= DefTermParamClause
* | UsingParamClause
*
Expand Down Expand Up @@ -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]
*/
Expand Down Expand Up @@ -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
Expand All @@ -3613,7 +3626,7 @@ object Parsers {
joinParams(tparams, vparamss)

var tpt = fromWithinReturnType { typedOpt() }

if (migrateTo3) newLineOptWhenFollowedBy(LBRACE)
val rhs =
if in.token == EQUALS then
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
if ctx.mode.is(Mode.SafeNulls)
&& !exprCtx.mode.is(Mode.SafeNulls)
&& pt.isValueType
&& !tree.isType
&& !inContext(exprCtx.addMode(Mode.SafeNulls))(expr1.tpe <:< pt) then
expr1 = expr1.cast(pt)

Expand Down
4 changes: 3 additions & 1 deletion docs/_docs/reference/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/pos-macros/i7264.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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`] ] =>
}
}