Skip to content
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

Simplify parameter handling in Parser #18993

Merged
merged 1 commit into from
Nov 21, 2023
Merged
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
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
Loading