Skip to content

Commit

Permalink
Simplify parameter handling in Parser (#18993)
Browse files Browse the repository at this point in the history
  • Loading branch information
hamzaremmal authored Nov 21, 2023
2 parents 7af5cfe + a6f8167 commit 5d142ff
Showing 1 changed file with 63 additions and 60 deletions.
123 changes: 63 additions & 60 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,23 @@ object Parsers {
case ElseWhere extends Location(false, false, false)

enum ParamOwner:
case Class, Type, TypeParam, Def
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 Given // given definition
case ExtensionPrefix // extension clause, up to and including extension parameter
case ExtensionFollow // extension clause, following extension parameter

def isClass = // owner is a class
this == Class || this == CaseClass
def takesOnlyUsingClauses = // only using clauses allowed for this owner
this == Given || this == ExtensionFollow
def acceptsVariance =
this == Class || this == CaseClass || this == Type

end ParamOwner

enum ParseKind:
case Expr, Type, Pattern
Expand Down Expand Up @@ -3214,33 +3230,29 @@ object Parsers {
* | UsingParamClause
*/
def typeOrTermParamClauses(
ownerKind: ParamOwner,
numLeadParams: Int = 0
): List[List[TypeDef] | List[ValDef]] =
paramOwner: ParamOwner, numLeadParams: Int = 0): List[List[TypeDef] | List[ValDef]] =

def recur(firstClause: Boolean, numLeadParams: Int, prevIsTypeClause: Boolean): List[List[TypeDef] | List[ValDef]] =
def recur(numLeadParams: Int, firstClause: Boolean, prevIsTypeClause: Boolean): List[List[TypeDef] | List[ValDef]] =
newLineOptWhenFollowedBy(LPAREN)
newLineOptWhenFollowedBy(LBRACKET)
if in.token == LPAREN then
val paramsStart = in.offset
val params = termParamClause(
numLeadParams,
firstClause = firstClause)
val params = termParamClause(paramOwner, numLeadParams, firstClause)
val lastClause = params.nonEmpty && params.head.mods.flags.is(Implicit)
params :: (
if lastClause then Nil
else recur(firstClause = false, numLeadParams + params.length, prevIsTypeClause = false))
else recur(numLeadParams + params.length, firstClause = false, prevIsTypeClause = false))
else if in.token == LBRACKET then
if prevIsTypeClause then
syntaxError(
em"Type parameter lists must be separated by a term or using parameter list",
in.offset
)
typeParamClause(ownerKind) :: recur(firstClause, numLeadParams, prevIsTypeClause = true)
typeParamClause(paramOwner) :: recur(numLeadParams, firstClause, prevIsTypeClause = true)
else Nil
end recur

recur(firstClause = true, numLeadParams = numLeadParams, prevIsTypeClause = false)
recur(numLeadParams, firstClause = true, prevIsTypeClause = false)
end typeOrTermParamClauses


Expand All @@ -3259,19 +3271,20 @@ object Parsers {
* HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
* HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypePamClause] | ‘_’) TypeBounds
*/
def typeParamClause(ownerKind: ParamOwner): List[TypeDef] = inBracketsWithCommas {
def typeParamClause(paramOwner: ParamOwner): List[TypeDef] = inBracketsWithCommas {

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

def typeParam(): TypeDef = {
val isAbstractOwner = ownerKind == ParamOwner.Type || ownerKind == ParamOwner.TypeParam
val isAbstractOwner = paramOwner == ParamOwner.Type || paramOwner == ParamOwner.TypeParam
val start = in.offset
var mods = annotsAsMods() | Param
if ownerKind == ParamOwner.Class then mods |= PrivateLocal
if paramOwner == ParamOwner.Class || paramOwner == ParamOwner.CaseClass then
mods |= PrivateLocal
if isIdent(nme.raw.PLUS) && checkVarianceOK() then
mods |= Covariant
else if isIdent(nme.raw.MINUS) && checkVarianceOK() then
Expand All @@ -3291,16 +3304,16 @@ object Parsers {
commaSeparated(() => typeParam())
}

def typeParamClauseOpt(ownerKind: ParamOwner): List[TypeDef] =
if (in.token == LBRACKET) typeParamClause(ownerKind) else Nil
def typeParamClauseOpt(paramOwner: ParamOwner): List[TypeDef] =
if (in.token == LBRACKET) typeParamClause(paramOwner) else Nil

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

/** ClsTermParamClause ::= ‘(’ ClsParams ‘)’ | UsingClsTermParamClause
Expand All @@ -3322,11 +3335,8 @@ object Parsers {
* @return the list of parameter definitions
*/
def termParamClause(
paramOwner: ParamOwner,
numLeadParams: Int, // number of parameters preceding this clause
ofClass: Boolean = false, // owner is a class
ofCaseClass: Boolean = false, // owner is a case class
prefix: Boolean = false, // clause precedes name of an extension method
givenOnly: Boolean = false, // only given parameters allowed
firstClause: Boolean = false // clause is the first in regular list of clauses
): List[ValDef] = {
var impliedMods: Modifiers = EmptyModifiers
Expand All @@ -3345,7 +3355,7 @@ object Parsers {
var mods = impliedMods.withAnnotations(annotations())
if isErasedKw then
mods = addModifier(mods)
if (ofClass) {
if paramOwner.isClass then
mods = addFlag(modifiers(start = mods), ParamAccessor)
mods =
if in.token == VAL then
Expand All @@ -3357,9 +3367,8 @@ object Parsers {
else
if (!(mods.flags &~ (ParamAccessor | Inline | Erased | impliedMods.flags)).isEmpty)
syntaxError(em"`val` or `var` expected")
if (firstClause && ofCaseClass) mods
if firstClause && paramOwner == ParamOwner.CaseClass then mods
else mods | PrivateLocal
}
else {
if (isIdent(nme.inline) && in.isSoftModifierInParamModifierPosition)
mods = addModifier(mods)
Expand All @@ -3368,7 +3377,7 @@ object Parsers {
atSpan(start, nameStart) {
val name = ident()
acceptColon()
if (in.token == ARROW && ofClass && !mods.is(Local))
if (in.token == ARROW && paramOwner.isClass && !mods.is(Local))
syntaxError(VarValParametersMayNotBeCallByName(name, mods.is(Mutable)))
// needed?, it's checked later anyway
val tpt = paramType()
Expand Down Expand Up @@ -3397,13 +3406,17 @@ object Parsers {

// begin termParamClause
inParensWithCommas {
if in.token == RPAREN && !prefix && !impliedMods.is(Given) then Nil
if in.token == RPAREN && paramOwner != ParamOwner.ExtensionPrefix && !impliedMods.is(Given)
then Nil
else
val clause =
if prefix && !isIdent(nme.using) && !isIdent(nme.erased) then param() :: Nil
if paramOwner == ParamOwner.ExtensionPrefix
&& !isIdent(nme.using) && !isIdent(nme.erased)
then
param() :: Nil
else
paramMods()
if givenOnly && !impliedMods.is(Given) then
if paramOwner.takesOnlyUsingClauses && !impliedMods.is(Given) then
syntaxError(em"`using` expected")
val (firstParamMod, isParams) =
var mods = EmptyModifiers
Expand All @@ -3417,7 +3430,7 @@ object Parsers {
|| isIdent && (in.name == nme.inline || in.lookahead.isColon)
(mods, isParams)
(if isParams then commaSeparated(() => param())
else contextTypes(ofClass, numLeadParams, impliedMods)) match {
else contextTypes(paramOwner, numLeadParams, impliedMods)) match {
case Nil => Nil
case (h :: t) => h.withAddedFlags(firstParamMod.flags) :: t
}
Expand All @@ -3431,31 +3444,21 @@ object Parsers {
*
* @return The parameter definitions
*/
def termParamClauses(
ofClass: Boolean = false,
ofCaseClass: Boolean = false,
givenOnly: Boolean = false,
numLeadParams: Int = 0
): List[List[ValDef]] =
def termParamClauses(paramOwner: ParamOwner, numLeadParams: Int = 0): List[List[ValDef]] =

def recur(firstClause: Boolean, numLeadParams: Int): List[List[ValDef]] =
def recur(numLeadParams: Int, firstClause: Boolean): List[List[ValDef]] =
newLineOptWhenFollowedBy(LPAREN)
if in.token == LPAREN then
val paramsStart = in.offset
val params = termParamClause(
numLeadParams,
ofClass = ofClass,
ofCaseClass = ofCaseClass,
givenOnly = givenOnly,
firstClause = firstClause)
val params = termParamClause(paramOwner, numLeadParams, firstClause)
val lastClause = params.nonEmpty && params.head.mods.flags.is(Implicit)
params :: (
if lastClause then Nil
else recur(firstClause = false, numLeadParams + params.length))
else recur(numLeadParams + params.length, firstClause = false))
else Nil
end recur

recur(firstClause = true, numLeadParams)
recur(numLeadParams, firstClause = true)
end termParamClauses

/* -------- DEFS ------------------------------------------- */
Expand Down Expand Up @@ -3727,7 +3730,7 @@ object Parsers {

if (in.token == THIS) {
in.nextToken()
val vparamss = termParamClauses(numLeadParams = numLeadParams)
val vparamss = termParamClauses(ParamOwner.Def, numLeadParams)
if (vparamss.isEmpty || vparamss.head.take(1).exists(_.mods.isOneOf(GivenOrImplicit)))
in.token match {
case LBRACKET => syntaxError(em"no type parameters allowed here")
Expand All @@ -3748,10 +3751,10 @@ object Parsers {
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)
typeOrTermParamClauses(ParamOwner.Def, numLeadParams)
else
val tparams = typeParamClauseOpt(ParamOwner.Def)
val vparamss = termParamClauses(numLeadParams = numLeadParams)
val vparamss = termParamClauses(ParamOwner.Def, numLeadParams)

joinParams(tparams, vparamss)

Expand Down Expand Up @@ -3892,16 +3895,16 @@ object Parsers {
}

def classDefRest(start: Offset, mods: Modifiers, name: TypeName): TypeDef =
val constr = classConstr(isCaseClass = mods.is(Case))
val constr = classConstr(if mods.is(Case) then ParamOwner.CaseClass else ParamOwner.Class)
val templ = templateOpt(constr)
finalizeDef(TypeDef(name, templ), mods, start)

/** ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsTermParamClauses
*/
def classConstr(isCaseClass: Boolean = false): DefDef = atSpan(in.lastOffset) {
val tparams = typeParamClauseOpt(ParamOwner.Class)
def classConstr(paramOwner: ParamOwner): DefDef = atSpan(in.lastOffset) {
val tparams = typeParamClauseOpt(paramOwner)
val cmods = fromWithinClassConstr(constrModsOpt())
val vparamss = termParamClauses(ofClass = true, ofCaseClass = isCaseClass)
val vparamss = termParamClauses(paramOwner)
makeConstructor(tparams, vparamss).withMods(cmods)
}

Expand Down Expand Up @@ -3930,7 +3933,7 @@ object Parsers {
val mods1 = checkAccessOnly(mods, "definitions")
val modulName = ident()
val clsName = modulName.toTypeName
val constr = classConstr()
val constr = classConstr(ParamOwner.Class)
val templ = template(constr, isEnum = true)
finalizeDef(TypeDef(clsName, templ), mods1, start)
}
Expand All @@ -3952,7 +3955,7 @@ object Parsers {
val caseDef =
if (in.token == LBRACKET || in.token == LPAREN || in.token == AT || isModifier) {
val clsName = id.name.toTypeName
val constr = classConstr(isCaseClass = true)
val constr = classConstr(ParamOwner.CaseClass)
TypeDef(clsName, caseTemplate(constr))
}
else
Expand Down Expand Up @@ -3999,11 +4002,11 @@ object Parsers {
val name = if isIdent && followingIsGivenSig() then ident() else EmptyTermName

val gdef =
val tparams = typeParamClauseOpt(ParamOwner.Def)
val tparams = typeParamClauseOpt(ParamOwner.Given)
newLineOpt()
val vparamss =
if in.token == LPAREN && in.lookahead.isIdent(nme.using)
then termParamClauses(givenOnly = true)
then termParamClauses(ParamOwner.Given)
else Nil
newLinesOpt()
val noParams = tparams.isEmpty && vparamss.isEmpty
Expand Down Expand Up @@ -4043,15 +4046,15 @@ object Parsers {
*/
def extension(): ExtMethods =
val start = in.skipToken()
val tparams = typeParamClauseOpt(ParamOwner.Def)
val tparams = typeParamClauseOpt(ParamOwner.ExtensionPrefix)
val leadParamss = ListBuffer[List[ValDef]]()
def numLeadParams = leadParamss.map(_.length).sum
while
val extParams = termParamClause(numLeadParams, prefix = true)
val extParams = termParamClause(ParamOwner.ExtensionPrefix, numLeadParams)
leadParamss += extParams
isUsingClause(extParams)
do ()
leadParamss ++= termParamClauses(givenOnly = true, numLeadParams = numLeadParams)
leadParamss ++= termParamClauses(ParamOwner.ExtensionFollow, numLeadParams)
if in.isColon then
syntaxError(em"no `:` expected here")
in.nextToken()
Expand Down

0 comments on commit 5d142ff

Please sign in to comment.