Skip to content

Commit

Permalink
Clean up categorization of type parameters (#21237)
Browse files Browse the repository at this point in the history
There are 4 categories, depending on whether

 (1) context bounds are allowed and
 (2) variances are allowed

```
Class: yes/yes
Type:  no/no
Hk:    no/yes
Def:   yes/no
```

Furthermore, Type and Hk parameters can be wildcards. The previous
grammars confused Type and Hk parameters and contained other errors as
well.
  • Loading branch information
odersky authored Aug 5, 2024
2 parents 7f5e4ce + 8c07ebd commit 1790bb5
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 47 deletions.
51 changes: 28 additions & 23 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ object Parsers {
enum ParamOwner:
case Class // class or trait or enum
case CaseClass // case class or enum case
case Type // type alias or abstract type
case TypeParam // type parameter
case Def // method
case Type // type alias or abstract type or polyfunction type/expr
case Hk // type parameter (i.e. current parameter is higher-kinded)
case Given // given definition
case ExtensionPrefix // extension clause, up to and including extension parameter
case ExtensionFollow // extension clause, following extension parameter
Expand All @@ -66,7 +66,11 @@ object Parsers {
def takesOnlyUsingClauses = // only using clauses allowed for this owner
this == Given || this == ExtensionFollow
def acceptsVariance =
this == Class || this == CaseClass || this == Type
this == Class || this == CaseClass || this == Hk
def acceptsCtxBounds =
!(this == Type || this == Hk)
def acceptsWildcard =
this == Type || this == Hk

end ParamOwner

Expand Down Expand Up @@ -1572,15 +1576,15 @@ object Parsers {
else core()

/** Type ::= FunType
* | HkTypeParamClause ‘=>>’ Type
* | TypTypeParamClause ‘=>>’ Type
* | FunParamClause ‘=>>’ Type
* | MatchType
* | InfixType
* FunType ::= (MonoFunType | PolyFunType)
* MonoFunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
* | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions
* PolyFunType ::= HKTypeParamClause '=>' Type
* | HKTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions
* | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions
* PolyFunType ::= TypTypeParamClause '=>' Type
* | TypTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions
* FunTypeArgs ::= InfixType
* | `(' [ FunArgType {`,' FunArgType } ] `)'
* | '(' [ TypedFunParam {',' TypedFunParam } ')'
Expand Down Expand Up @@ -1746,7 +1750,7 @@ object Parsers {
simpleTypeRest(tuple)
else if in.token == LBRACKET then
val start = in.offset
val tparams = typeParamClause(ParamOwner.TypeParam)
val tparams = typeParamClause(ParamOwner.Type)
if in.token == TLARROW then
atSpan(start, in.skipToken()):
LambdaTypeTree(tparams, toplevelTyp())
Expand Down Expand Up @@ -2299,15 +2303,15 @@ object Parsers {
t

/** Expr ::= [`implicit'] FunParams (‘=>’ | ‘?=>’) Expr
* | HkTypeParamClause ‘=>’ Expr
* | TypTypeParamClause ‘=>’ Expr
* | Expr1
* FunParams ::= Bindings
* | id
* | `_'
* ExprInParens ::= PostfixExpr `:' Type
* | Expr
* BlockResult ::= [‘implicit’] FunParams (‘=>’ | ‘?=>’) Block
* | HkTypeParamClause ‘=>’ Block
* | TypTypeParamClause ‘=>’ Block
* | Expr1
* Expr1 ::= [‘inline’] `if' `(' Expr `)' {nl} Expr [[semi] else Expr]
* | [‘inline’] `if' Expr `then' Expr [[semi] else Expr]
Expand Down Expand Up @@ -2343,7 +2347,7 @@ object Parsers {
closure(start, location, modifiers(BitSet(IMPLICIT)))
case LBRACKET =>
val start = in.offset
val tparams = typeParamClause(ParamOwner.TypeParam)
val tparams = typeParamClause(ParamOwner.Type)
val arrowOffset = accept(ARROW)
val body = expr(location)
atSpan(start, arrowOffset) {
Expand Down Expand Up @@ -2676,7 +2680,7 @@ object Parsers {
* ColonArgument ::= colon [LambdaStart]
* indent (CaseClauses | Block) outdent
* LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
* | HkTypeParamClause ‘=>’
* | TypTypeParamClause ‘=>’
* ColonArgBody ::= indent (CaseClauses | Block) outdent
* Quoted ::= ‘'’ ‘{’ Block ‘}’
* | ‘'’ ‘[’ Type ‘]’
Expand Down Expand Up @@ -3409,17 +3413,19 @@ object Parsers {

/** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
* ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
* id [HkTypeParamClause] TypeParamBounds
* id [HkTypeParamClause] TypeAndCtxBounds
*
* DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
* DefTypeParam ::= {Annotation}
* id [HkTypeParamClause] TypeParamBounds
* id [HkTypeParamClause] TypeAndCtxBounds
*
* TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
* TypTypeParam ::= {Annotation} id [HkTypePamClause] TypeBounds
* TypTypeParam ::= {Annotation}
* (id | ‘_’) [HkTypeParamClause] TypeBounds
*
* HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
* HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypePamClause] | ‘_’) TypeBounds
* HkTypeParam ::= {Annotation} [‘+’ | ‘-’]
* (id | ‘_’) [HkTypePamClause] TypeBounds
*/
def typeParamClause(paramOwner: ParamOwner): List[TypeDef] = inBracketsWithCommas {

Expand All @@ -3430,7 +3436,6 @@ object Parsers {
ok

def typeParam(): TypeDef = {
val isAbstractOwner = paramOwner == ParamOwner.Type || paramOwner == ParamOwner.TypeParam
val start = in.offset
var mods = annotsAsMods() | Param
if paramOwner.isClass then
Expand All @@ -3441,13 +3446,13 @@ object Parsers {
mods |= Contravariant
atSpan(start, nameStart) {
val name =
if (isAbstractOwner && in.token == USCORE) {
if paramOwner.acceptsWildcard && in.token == USCORE then
in.nextToken()
WildcardParamName.fresh().toTypeName
}
else ident().toTypeName
val hkparams = typeParamClauseOpt(ParamOwner.Type)
val bounds = if (isAbstractOwner) typeBounds() else typeAndCtxBounds(name)
val hkparams = typeParamClauseOpt(ParamOwner.Hk)
val bounds =
if paramOwner.acceptsCtxBounds then typeAndCtxBounds(name) else typeBounds()
TypeDef(name, lambdaAbstract(hkparams, bounds)).withMods(mods)
}
}
Expand Down Expand Up @@ -3963,14 +3968,14 @@ object Parsers {
argumentExprss(mkApply(Ident(nme.CONSTRUCTOR), argumentExprs()))
}

/** TypeDef ::= id [TypeParamClause] {FunParamClause} TypeAndCtxBounds [‘=’ Type]
/** TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds [‘=’ Type]
*/
def typeDefOrDcl(start: Offset, mods: Modifiers): Tree = {
newLinesOpt()
atSpan(start, nameStart) {
val nameIdent = typeIdent()
val tname = nameIdent.name.asTypeName
val tparams = typeParamClauseOpt(ParamOwner.Type)
val tparams = typeParamClauseOpt(ParamOwner.Hk)
val vparamss = funParamClauses()

def makeTypeDef(rhs: Tree): Tree = {
Expand Down
22 changes: 11 additions & 11 deletions docs/_docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,12 @@ ClassQualifier ::= ‘[’ id ‘]’
### Types
```ebnf
Type ::= FunType
| HkTypeParamClause ‘=>>’ Type LambdaTypeTree(ps, t)
| TypTypeParamClause ‘=>>’ Type LambdaTypeTree(ps, t)
| FunParamClause ‘=>>’ Type TermLambdaTypeTree(ps, t)
| MatchType
| InfixType
FunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type Function(ts, t) | FunctionWithMods(ts, t, mods, erasedParams)
| HKTypeParamClause '=>' Type PolyFunction(ps, t)
| TypTypeParamClause '=>' Type PolyFunction(ps, t)
FunTypeArgs ::= InfixType
| ‘(’ [ FunArgTypes ] ‘)’
| FunParamClause
Expand Down Expand Up @@ -233,10 +233,10 @@ NameAndType ::= id ':' Type
### Expressions
```ebnf
Expr ::= FunParams (‘=>’ | ‘?=>’) Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
| HkTypeParamClause ‘=>’ Expr PolyFunction(ts, expr)
| TypTypeParamClause ‘=>’ Expr PolyFunction(ts, expr)
| Expr1
BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
| HkTypeParamClause ‘=>’ Block
| TypTypeParamClause ‘=>’ Block
| Expr1
FunParams ::= Bindings
| id
Expand Down Expand Up @@ -286,7 +286,7 @@ SimpleExpr ::= SimpleRef
ColonArgument ::= colon [LambdaStart]
indent (CaseClauses | Block) outdent
LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
| HkTypeParamClause ‘=>’
| TypTypeParamClause ‘=>’
Quoted ::= ‘'’ ‘{’ Block ‘}’
| ‘'’ ‘[’ TypeBlock ‘]’
ExprSplice ::= spliceId -- if inside quoted block
Expand Down Expand Up @@ -364,11 +364,14 @@ ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] TypeDef(Modifiers, name, tparams, bounds)
id [HkTypeParamClause] TypeAndCtxBounds Bound(below, above, context)
DefTypeParamClause::= [nl] ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeAndCtxBounds
TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
TypTypeParam ::= {Annotation} id [HkTypeParamClause] TypeBounds
TypTypeParam ::= {Annotation} (id | ‘_’) [HkTypeParamClause] TypeBounds
HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypeParamClause] | ‘_’)
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id | ‘_’) [HkTypeParamClause]
TypeBounds
ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
Expand All @@ -385,9 +388,6 @@ DefParamClause ::= DefTypeParamClause
TypelessClauses ::= TypelessClause {TypelessClause}
TypelessClause ::= DefTermParamClause
| UsingParamClause
DefTypeParamClause::= [nl] ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeAndCtxBounds
DefTermParamClause::= [nl] ‘(’ [DefTermParams] ‘)’
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefTermParams | FunArgTypes) ‘)’
DefImplicitClause ::= [nl] ‘(’ ‘implicit’ DefTermParams ‘)’
Expand Down Expand Up @@ -458,7 +458,7 @@ PatDef ::= ids [‘:’ Type] [‘=’ Expr]
DefDef ::= DefSig [‘:’ Type] [‘=’ Expr] DefDef(_, name, paramss, tpe, expr)
| ‘this’ TypelessClauses [DefImplicitClause] ‘=’ ConstrExpr DefDef(_, <init>, vparamss, EmptyTree, expr | Block)
DefSig ::= id [DefParamClauses] [DefImplicitClause]
TypeDef ::= id [TypeParamClause] {FunParamClause} TypeAndCtxBounds TypeDefTree(_, name, tparams, bound
TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds TypeDefTree(_, name, tparams, bound
[‘=’ Type]
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
Expand Down
26 changes: 13 additions & 13 deletions docs/_docs/reference/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,11 @@ ClassQualifier ::= ‘[’ id ‘]’
### Types
```
Type ::= FunType
| HkTypeParamClause ‘=>>’ Type
| FunParamClause ‘=>>’ Type
| TypTypeParamClause ‘=>>’ Type
| MatchType
| InfixType
FunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
| HKTypeParamClause '=>' Type
| TypTypeParamClause '=>' Type
FunTypeArgs ::= InfixType
| ‘(’ [ FunArgTypes ] ‘)’
| FunParamClause
Expand Down Expand Up @@ -215,17 +214,17 @@ ParamValueType ::= Type [‘*’]
TypeArgs ::= ‘[’ Types ‘]’
Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>>
TypeBounds ::= [‘>:’ Type] [‘<:’ Type]
TypeParamBounds ::= TypeBounds {‘:’ Type}
TypeAndCtxBounds ::= TypeBounds {‘:’ Type}
Types ::= Type {‘,’ Type}
```

### Expressions
```
Expr ::= FunParams (‘=>’ | ‘?=>’) Expr
| HkTypeParamClause ‘=>’ Expr
| TypTypeParamClause ‘=>’ Expr
| Expr1
BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
| HkTypeParamClause ‘=>’ Block
| TypTypeParamClause ‘=>’ Block
| Expr1
FunParams ::= Bindings
| id
Expand Down Expand Up @@ -273,7 +272,7 @@ SimpleExpr ::= SimpleRef
ColonArgument ::= colon [LambdaStart]
indent (CaseClauses | Block) outdent
LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
| HkTypeParamClause ‘=>’
| TypTypeParamClause ‘=>’
Quoted ::= ‘'’ ‘{’ Block ‘}’
| ‘'’ ‘[’ TypeBlock ‘]’
ExprSplice ::= spliceId -- if inside quoted block
Expand Down Expand Up @@ -339,13 +338,16 @@ ArgumentPatterns ::= ‘(’ [Patterns] ‘)’
### Type and Value Parameters
```
ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] id [HkTypeParamClause] TypeParamBounds
ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] id [HkTypeParamClause] TypeAndCtxBounds
DefTypeParamClause::= [nl] ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeAndCtxBounds
TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
TypTypeParam ::= {Annotation} id [HkTypeParamClause] TypeBounds
TypTypeParam ::= {Annotation} (id | ‘_’) [HkTypeParamClause] TypeBounds
HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypeParamClause] | ‘_’) TypeBounds
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id | ‘_’) [HkTypeParamClause] TypeBounds
ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’
Expand All @@ -361,8 +363,6 @@ TypelessClauses ::= TypelessClause {TypelessClause}
TypelessClause ::= DefTermParamClause
| UsingParamClause
DefTypeParamClause::= [nl] ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds
DefTermParamClause::= [nl] ‘(’ [DefTermParams] ‘)’
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefTermParams | FunArgTypes) ‘)’
DefImplicitClause ::= [nl] ‘(’ ‘implicit’ DefTermParams ‘)’
Expand Down Expand Up @@ -431,7 +431,7 @@ PatDef ::= ids [‘:’ Type] [‘=’ Expr]
DefDef ::= DefSig [‘:’ Type] [‘=’ Expr] DefDef(_, name, paramss, tpe, expr)
| ‘this’ TypelessClauses [DefImplicitClause] ‘=’ ConstrExpr DefDef(_, <init>, vparamss, EmptyTree, expr | Block)
DefSig ::= id [DefParamClauses] [DefImplicitClause]
TypeDef ::= id [TypeParamClause] {FunParamClause} TypeBounds TypeDefTree(_, name, tparams, bound
TypeDef ::= id [HkTypeParamClause] {FunParamClause}TypeBounds TypeDefTree(_, name, tparams, bound
[‘=’ Type]
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
Expand Down

0 comments on commit 1790bb5

Please sign in to comment.