From a6f8167c67c3dcbbf5179fd0517c644e14696517 Mon Sep 17 00:00:00 2001 From: odersky Date: Sat, 18 Nov 2023 12:06:48 +0100 Subject: [PATCH] Simplify parameter handling in Parser --- .../dotty/tools/dotc/parsing/Parsers.scala | 123 +++++++++--------- 1 file changed, 63 insertions(+), 60 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index aec3ad42feef..a2cc6499e843 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) @@ -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() @@ -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 @@ -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 } @@ -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 ------------------------------------------- */ @@ -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") @@ -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) @@ -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) } @@ -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) } @@ -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 @@ -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 @@ -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()