Skip to content

Commit 1aea86b

Browse files
Backport "Simplify parameter handling in Parser" to LTS (#20760)
Backports #18993 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents ab667c5 + 57c4e4a commit 1aea86b

File tree

1 file changed

+65
-62
lines changed

1 file changed

+65
-62
lines changed

Diff for: compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+65-62
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,23 @@ object Parsers {
5151
case ElseWhere extends Location(false, false, false)
5252

5353
enum ParamOwner:
54-
case Class, Type, TypeParam, Def
54+
case Class // class or trait or enum
55+
case CaseClass // case class or enum case
56+
case Type // type alias or abstract type
57+
case TypeParam // type parameter
58+
case Def // method
59+
case Given // given definition
60+
case ExtensionPrefix // extension clause, up to and including extension parameter
61+
case ExtensionFollow // extension clause, following extension parameter
62+
63+
def isClass = // owner is a class
64+
this == Class || this == CaseClass
65+
def takesOnlyUsingClauses = // only using clauses allowed for this owner
66+
this == Given || this == ExtensionFollow
67+
def acceptsVariance =
68+
this == Class || this == CaseClass || this == Type
69+
70+
end ParamOwner
5571

5672
enum ParseKind:
5773
case Expr, Type, Pattern
@@ -3169,33 +3185,29 @@ object Parsers {
31693185
* | UsingParamClause
31703186
*/
31713187
def typeOrTermParamClauses(
3172-
ownerKind: ParamOwner,
3173-
numLeadParams: Int = 0
3174-
): List[List[TypeDef] | List[ValDef]] =
3188+
paramOwner: ParamOwner, numLeadParams: Int = 0): List[List[TypeDef] | List[ValDef]] =
31753189

3176-
def recur(firstClause: Boolean, numLeadParams: Int, prevIsTypeClause: Boolean): List[List[TypeDef] | List[ValDef]] =
3190+
def recur(numLeadParams: Int, firstClause: Boolean, prevIsTypeClause: Boolean): List[List[TypeDef] | List[ValDef]] =
31773191
newLineOptWhenFollowedBy(LPAREN)
31783192
newLineOptWhenFollowedBy(LBRACKET)
31793193
if in.token == LPAREN then
31803194
val paramsStart = in.offset
3181-
val params = termParamClause(
3182-
numLeadParams,
3183-
firstClause = firstClause)
3195+
val params = termParamClause(paramOwner, numLeadParams, firstClause)
31843196
val lastClause = params.nonEmpty && params.head.mods.flags.is(Implicit)
31853197
params :: (
31863198
if lastClause then Nil
3187-
else recur(firstClause = false, numLeadParams + params.length, prevIsTypeClause = false))
3199+
else recur(numLeadParams + params.length, firstClause = false, prevIsTypeClause = false))
31883200
else if in.token == LBRACKET then
31893201
if prevIsTypeClause then
31903202
syntaxError(
31913203
em"Type parameter lists must be separated by a term or using parameter list",
31923204
in.offset
31933205
)
3194-
typeParamClause(ownerKind) :: recur(firstClause, numLeadParams, prevIsTypeClause = true)
3206+
typeParamClause(paramOwner) :: recur(numLeadParams, firstClause, prevIsTypeClause = true)
31953207
else Nil
31963208
end recur
31973209

3198-
recur(firstClause = true, numLeadParams = numLeadParams, prevIsTypeClause = false)
3210+
recur(numLeadParams, firstClause = true, prevIsTypeClause = false)
31993211
end typeOrTermParamClauses
32003212

32013213

@@ -3214,21 +3226,22 @@ object Parsers {
32143226
* HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
32153227
* HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypePamClause] | ‘_’) TypeBounds
32163228
*/
3217-
def typeParamClause(ownerKind: ParamOwner): List[TypeDef] = inBracketsWithCommas {
3229+
def typeParamClause(paramOwner: ParamOwner): List[TypeDef] = inBracketsWithCommas {
32183230

32193231
def checkVarianceOK(): Boolean =
3220-
val ok = ownerKind != ParamOwner.Def && ownerKind != ParamOwner.TypeParam
3232+
val ok = paramOwner.acceptsVariance
32213233
if !ok then syntaxError(em"no `+/-` variance annotation allowed here")
32223234
in.nextToken()
32233235
ok
32243236

32253237
def typeParam(): TypeDef = {
3226-
val isAbstractOwner = ownerKind == ParamOwner.Type || ownerKind == ParamOwner.TypeParam
3238+
val isAbstractOwner = paramOwner == ParamOwner.Type || paramOwner == ParamOwner.TypeParam
32273239
val start = in.offset
32283240
var mods = annotsAsMods() | Param
3229-
if ownerKind == ParamOwner.Class then mods |= PrivateLocal
3241+
if paramOwner == ParamOwner.Class || paramOwner == ParamOwner.CaseClass then
3242+
mods |= PrivateLocal
32303243
if Feature.ccEnabled && in.token == SEALED then
3231-
if ownerKind == ParamOwner.Def then mods |= Sealed
3244+
if paramOwner == ParamOwner.Def then mods |= Sealed
32323245
else syntaxError(em"`sealed` modifier only allowed for method type parameters")
32333246
in.nextToken()
32343247
if isIdent(nme.raw.PLUS) && checkVarianceOK() then
@@ -3250,16 +3263,16 @@ object Parsers {
32503263
commaSeparated(() => typeParam())
32513264
}
32523265

3253-
def typeParamClauseOpt(ownerKind: ParamOwner): List[TypeDef] =
3254-
if (in.token == LBRACKET) typeParamClause(ownerKind) else Nil
3266+
def typeParamClauseOpt(paramOwner: ParamOwner): List[TypeDef] =
3267+
if (in.token == LBRACKET) typeParamClause(paramOwner) else Nil
32553268

32563269
/** ContextTypes ::= FunArgType {‘,’ FunArgType}
32573270
*/
3258-
def contextTypes(ofClass: Boolean, numLeadParams: Int, impliedMods: Modifiers): List[ValDef] =
3271+
def contextTypes(paramOwner: ParamOwner, numLeadParams: Int, impliedMods: Modifiers): List[ValDef] =
32593272
val tps = commaSeparated(funArgType)
32603273
var counter = numLeadParams
32613274
def nextIdx = { counter += 1; counter }
3262-
val paramFlags = if ofClass then LocalParamAccessor else Param
3275+
val paramFlags = if paramOwner.isClass then LocalParamAccessor else Param
32633276
tps.map(makeSyntheticParameter(nextIdx, _, paramFlags | Synthetic | impliedMods.flags))
32643277

32653278
/** ClsTermParamClause ::= ‘(’ ClsParams ‘)’ | UsingClsTermParamClause
@@ -3281,11 +3294,8 @@ object Parsers {
32813294
* @return the list of parameter definitions
32823295
*/
32833296
def termParamClause(
3297+
paramOwner: ParamOwner,
32843298
numLeadParams: Int, // number of parameters preceding this clause
3285-
ofClass: Boolean = false, // owner is a class
3286-
ofCaseClass: Boolean = false, // owner is a case class
3287-
prefix: Boolean = false, // clause precedes name of an extension method
3288-
givenOnly: Boolean = false, // only given parameters allowed
32893299
firstClause: Boolean = false // clause is the first in regular list of clauses
32903300
): List[ValDef] = {
32913301
var impliedMods: Modifiers = EmptyModifiers
@@ -3304,7 +3314,7 @@ object Parsers {
33043314
var mods = impliedMods.withAnnotations(annotations())
33053315
if isErasedKw then
33063316
mods = addModifier(mods)
3307-
if (ofClass) {
3317+
if paramOwner.isClass then
33083318
mods = addFlag(modifiers(start = mods), ParamAccessor)
33093319
mods =
33103320
if in.token == VAL then
@@ -3316,9 +3326,8 @@ object Parsers {
33163326
else
33173327
if (!(mods.flags &~ (ParamAccessor | Inline | Erased | impliedMods.flags)).isEmpty)
33183328
syntaxError(em"`val` or `var` expected")
3319-
if (firstClause && ofCaseClass) mods
3329+
if firstClause && paramOwner == ParamOwner.CaseClass then mods
33203330
else mods | PrivateLocal
3321-
}
33223331
else {
33233332
if (isIdent(nme.inline) && in.isSoftModifierInParamModifierPosition)
33243333
mods = addModifier(mods)
@@ -3327,7 +3336,7 @@ object Parsers {
33273336
atSpan(start, nameStart) {
33283337
val name = ident()
33293338
acceptColon()
3330-
if (in.token == ARROW && ofClass && !mods.is(Local))
3339+
if (in.token == ARROW && paramOwner.isClass && !mods.is(Local))
33313340
syntaxError(VarValParametersMayNotBeCallByName(name, mods.is(Mutable)))
33323341
// needed?, it's checked later anyway
33333342
val tpt = paramType()
@@ -3342,7 +3351,7 @@ object Parsers {
33423351

33433352
def checkVarArgsRules(vparams: List[ValDef]): Unit = vparams match {
33443353
case Nil =>
3345-
case _ :: Nil if !prefix =>
3354+
case _ :: Nil if paramOwner != ParamOwner.ExtensionPrefix =>
33463355
case vparam :: rest =>
33473356
vparam.tpt match {
33483357
case PostfixOp(_, op) if op.name == tpnme.raw.STAR =>
@@ -3354,13 +3363,17 @@ object Parsers {
33543363

33553364
// begin termParamClause
33563365
inParensWithCommas {
3357-
if in.token == RPAREN && !prefix && !impliedMods.is(Given) then Nil
3366+
if in.token == RPAREN && paramOwner != ParamOwner.ExtensionPrefix && !impliedMods.is(Given)
3367+
then Nil
33583368
else
33593369
val clause =
3360-
if prefix && !isIdent(nme.using) && !isIdent(nme.erased) then param() :: Nil
3370+
if paramOwner == ParamOwner.ExtensionPrefix
3371+
&& !isIdent(nme.using) && !isIdent(nme.erased)
3372+
then
3373+
param() :: Nil
33613374
else
33623375
paramMods()
3363-
if givenOnly && !impliedMods.is(Given) then
3376+
if paramOwner.takesOnlyUsingClauses && !impliedMods.is(Given) then
33643377
syntaxError(em"`using` expected")
33653378
val (firstParamMod, isParams) =
33663379
var mods = EmptyModifiers
@@ -3374,7 +3387,7 @@ object Parsers {
33743387
|| isIdent && (in.name == nme.inline || in.lookahead.isColon)
33753388
(mods, isParams)
33763389
(if isParams then commaSeparated(() => param())
3377-
else contextTypes(ofClass, numLeadParams, impliedMods)) match {
3390+
else contextTypes(paramOwner, numLeadParams, impliedMods)) match {
33783391
case Nil => Nil
33793392
case (h :: t) => h.withAddedFlags(firstParamMod.flags) :: t
33803393
}
@@ -3388,31 +3401,21 @@ object Parsers {
33883401
*
33893402
* @return The parameter definitions
33903403
*/
3391-
def termParamClauses(
3392-
ofClass: Boolean = false,
3393-
ofCaseClass: Boolean = false,
3394-
givenOnly: Boolean = false,
3395-
numLeadParams: Int = 0
3396-
): List[List[ValDef]] =
3404+
def termParamClauses(paramOwner: ParamOwner, numLeadParams: Int = 0): List[List[ValDef]] =
33973405

3398-
def recur(firstClause: Boolean, numLeadParams: Int): List[List[ValDef]] =
3406+
def recur(numLeadParams: Int, firstClause: Boolean): List[List[ValDef]] =
33993407
newLineOptWhenFollowedBy(LPAREN)
34003408
if in.token == LPAREN then
34013409
val paramsStart = in.offset
3402-
val params = termParamClause(
3403-
numLeadParams,
3404-
ofClass = ofClass,
3405-
ofCaseClass = ofCaseClass,
3406-
givenOnly = givenOnly,
3407-
firstClause = firstClause)
3410+
val params = termParamClause(paramOwner, numLeadParams, firstClause)
34083411
val lastClause = params.nonEmpty && params.head.mods.flags.is(Implicit)
34093412
params :: (
34103413
if lastClause then Nil
3411-
else recur(firstClause = false, numLeadParams + params.length))
3414+
else recur(numLeadParams + params.length, firstClause = false))
34123415
else Nil
34133416
end recur
34143417

3415-
recur(firstClause = true, numLeadParams)
3418+
recur(numLeadParams, firstClause = true)
34163419
end termParamClauses
34173420

34183421
/* -------- DEFS ------------------------------------------- */
@@ -3679,7 +3682,7 @@ object Parsers {
36793682

36803683
if (in.token == THIS) {
36813684
in.nextToken()
3682-
val vparamss = termParamClauses(numLeadParams = numLeadParams)
3685+
val vparamss = termParamClauses(ParamOwner.Def, numLeadParams)
36833686
if (vparamss.isEmpty || vparamss.head.take(1).exists(_.mods.isOneOf(GivenOrImplicit)))
36843687
in.token match {
36853688
case LBRACKET => syntaxError(em"no type parameters allowed here")
@@ -3700,10 +3703,10 @@ object Parsers {
37003703
val paramss =
37013704
if in.featureEnabled(Feature.clauseInterleaving) then
37023705
// If you are making interleaving stable manually, please refer to the PR introducing it instead, section "How to make non-experimental"
3703-
typeOrTermParamClauses(ParamOwner.Def, numLeadParams = numLeadParams)
3706+
typeOrTermParamClauses(ParamOwner.Def, numLeadParams)
37043707
else
37053708
val tparams = typeParamClauseOpt(ParamOwner.Def)
3706-
val vparamss = termParamClauses(numLeadParams = numLeadParams)
3709+
val vparamss = termParamClauses(ParamOwner.Def, numLeadParams)
37073710

37083711
joinParams(tparams, vparamss)
37093712

@@ -3842,16 +3845,16 @@ object Parsers {
38423845
}
38433846

38443847
def classDefRest(start: Offset, mods: Modifiers, name: TypeName): TypeDef =
3845-
val constr = classConstr(isCaseClass = mods.is(Case))
3848+
val constr = classConstr(if mods.is(Case) then ParamOwner.CaseClass else ParamOwner.Class)
38463849
val templ = templateOpt(constr)
38473850
finalizeDef(TypeDef(name, templ), mods, start)
38483851

38493852
/** ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsTermParamClauses
38503853
*/
3851-
def classConstr(isCaseClass: Boolean = false): DefDef = atSpan(in.lastOffset) {
3852-
val tparams = typeParamClauseOpt(ParamOwner.Class)
3854+
def classConstr(paramOwner: ParamOwner): DefDef = atSpan(in.lastOffset) {
3855+
val tparams = typeParamClauseOpt(paramOwner)
38533856
val cmods = fromWithinClassConstr(constrModsOpt())
3854-
val vparamss = termParamClauses(ofClass = true, ofCaseClass = isCaseClass)
3857+
val vparamss = termParamClauses(paramOwner)
38553858
makeConstructor(tparams, vparamss).withMods(cmods)
38563859
}
38573860

@@ -3880,7 +3883,7 @@ object Parsers {
38803883
val mods1 = checkAccessOnly(mods, "definitions")
38813884
val modulName = ident()
38823885
val clsName = modulName.toTypeName
3883-
val constr = classConstr()
3886+
val constr = classConstr(ParamOwner.Class)
38843887
val templ = template(constr, isEnum = true)
38853888
finalizeDef(TypeDef(clsName, templ), mods1, start)
38863889
}
@@ -3902,7 +3905,7 @@ object Parsers {
39023905
val caseDef =
39033906
if (in.token == LBRACKET || in.token == LPAREN || in.token == AT || isModifier) {
39043907
val clsName = id.name.toTypeName
3905-
val constr = classConstr(isCaseClass = true)
3908+
val constr = classConstr(ParamOwner.CaseClass)
39063909
TypeDef(clsName, caseTemplate(constr))
39073910
}
39083911
else
@@ -3949,11 +3952,11 @@ object Parsers {
39493952
val name = if isIdent && followingIsGivenSig() then ident() else EmptyTermName
39503953

39513954
val gdef =
3952-
val tparams = typeParamClauseOpt(ParamOwner.Def)
3955+
val tparams = typeParamClauseOpt(ParamOwner.Given)
39533956
newLineOpt()
39543957
val vparamss =
39553958
if in.token == LPAREN && in.lookahead.isIdent(nme.using)
3956-
then termParamClauses(givenOnly = true)
3959+
then termParamClauses(ParamOwner.Given)
39573960
else Nil
39583961
newLinesOpt()
39593962
val noParams = tparams.isEmpty && vparamss.isEmpty
@@ -3993,15 +3996,15 @@ object Parsers {
39933996
*/
39943997
def extension(): ExtMethods =
39953998
val start = in.skipToken()
3996-
val tparams = typeParamClauseOpt(ParamOwner.Def)
3999+
val tparams = typeParamClauseOpt(ParamOwner.ExtensionPrefix)
39974000
val leadParamss = ListBuffer[List[ValDef]]()
39984001
def numLeadParams = leadParamss.map(_.length).sum
39994002
while
4000-
val extParams = termParamClause(numLeadParams, prefix = true)
4003+
val extParams = termParamClause(ParamOwner.ExtensionPrefix, numLeadParams)
40014004
leadParamss += extParams
40024005
isUsingClause(extParams)
40034006
do ()
4004-
leadParamss ++= termParamClauses(givenOnly = true, numLeadParams = numLeadParams)
4007+
leadParamss ++= termParamClauses(ParamOwner.ExtensionFollow, numLeadParams)
40054008
if in.isColon then
40064009
syntaxError(em"no `:` expected here")
40074010
in.nextToken()

0 commit comments

Comments
 (0)