Skip to content

Commit 7b57ad6

Browse files
committed
Refactorings: maybeParams
Niw is parameterized to also accept regular param clauses with default parameters.
1 parent 4f8dd1e commit 7b57ad6

File tree

4 files changed

+79
-66
lines changed

4 files changed

+79
-66
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 73 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,10 @@ object Parsers {
968968
val next = in.lookahead.token
969969
next == LBRACKET || next == LPAREN
970970

971+
def followingIsParam(): Boolean =
972+
startParamTokens.contains(in.token)
973+
|| isIdent && (in.name == nme.inline || in.lookahead.token == COLON)
974+
971975
/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
972976

973977
var opStack: List[OpInfo] = Nil
@@ -1441,7 +1445,8 @@ object Parsers {
14411445

14421446
val t =
14431447
if in.token == LPAREN then
1444-
afterArguments(x => infixTypeRest(refinedTypeRest(withTypeRest(x))), functionRest)
1448+
def normalTypeRest(t: Tree) = infixTypeRest(refinedTypeRest(withTypeRest(t)))
1449+
maybeParams(typedFunParams, normalTypeRest, functionRest)
14451450
else if (in.token == LBRACKET) {
14461451
val tparams = typeParamClause(ParamOwner.TypeParam)
14471452
if (in.token == TLARROW)
@@ -1474,14 +1479,18 @@ object Parsers {
14741479
}
14751480
}
14761481

1477-
def funArgTypesRest(first: Tree, following: () => Tree): List[Tree] =
1478-
val buf = new ListBuffer[Tree] += first
1479-
while in.token == COMMA do
1480-
in.nextToken()
1481-
buf += following()
1482-
buf.toList
1483-
1484-
def afterArguments[T](parseSimple: Tree => T, parseFn: (List[Tree], Modifiers) => T): T =
1482+
/** Either a parameter list, which then needs to be followed by `=>` or
1483+
* a type or constructor application.
1484+
*
1485+
* @param parseParams The parsing method for the parameters inside `(...)`
1486+
* @param parseSimple The parsing continuation if the prefix is not a parameter list
1487+
* or the prefix is not followed by `=>` or `?=>`
1488+
* @param parseFn The parsing continuation to follow otherwise.
1489+
*/
1490+
def maybeParams[T](
1491+
parseParams: Modifiers => List[ValDef],
1492+
parseSimple: Tree => T,
1493+
parseFn: (List[Tree], Modifiers) => T): T =
14851494
val start = in.offset
14861495
in.nextToken()
14871496
var imods = Modifiers()
@@ -1493,17 +1502,11 @@ object Parsers {
14931502
openParens.change(LPAREN, 1)
14941503
imods = modifiers(funTypeArgMods)
14951504
val paramStart = in.offset
1496-
val ts = funArgType() match
1497-
case Ident(name) if name != tpnme.WILDCARD && in.token == COLON =>
1498-
isValParamList = true
1499-
funArgTypesRest(
1500-
typedFunParam(paramStart, name.toTermName, imods),
1501-
() => typedFunParam(in.offset, ident(), imods))
1502-
case t =>
1503-
funArgTypesRest(t, funArgType)
1505+
val isParams = followingIsParam()
1506+
val ts = if isParams then parseParams(imods) else funArgTypes()
15041507
openParens.change(LPAREN, -1)
15051508
accept(RPAREN)
1506-
if isValParamList || in.token == ARROW || in.token == CTXARROW then
1509+
if isParams || in.token == ARROW || in.token == CTXARROW then
15071510
parseFn(ts, imods)
15081511
else
15091512
val ts1 =
@@ -1516,7 +1519,7 @@ object Parsers {
15161519
t
15171520
val tuple = atSpan(start) { makeTupleOrParens(ts1) }
15181521
parseSimple(annotTypeRest(simpleTypeRest(tuple)))
1519-
end afterArguments
1522+
end maybeParams
15201523

15211524
private def makeKindProjectorTypeDef(name: TypeName): TypeDef =
15221525
TypeDef(name, WildcardTypeBoundsTree()).withFlags(Param)
@@ -1548,10 +1551,12 @@ object Parsers {
15481551
makeParameter(name, typ(), mods)
15491552
}
15501553

1554+
def typedFunParams(mods: Modifiers = EmptyModifiers): List[ValDef] =
1555+
commaSeparated(() => typedFunParam(in.offset, ident(), mods))
1556+
15511557
/** FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
15521558
*/
1553-
def funParamClause(): List[ValDef] =
1554-
inParens(commaSeparated(() => typedFunParam(in.offset, ident())))
1559+
def funParamClause(): List[ValDef] = inParens(typedFunParams())
15551560

15561561
def funParamClauses(): List[List[ValDef]] =
15571562
if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
@@ -1796,6 +1801,10 @@ object Parsers {
17961801
if (in.token == ARROW) atSpan(in.skipToken()) { ByNameTypeTree(typ()) }
17971802
else typ()
17981803

1804+
/** FunArgTypes ::= FunArgType { `,` FunArgType}
1805+
*/
1806+
def funArgTypes(): List[Tree] = commaSeparated(funArgType)
1807+
17991808
/** ParamType ::= [`=>'] ParamValueType
18001809
*/
18011810
def paramType(): Tree =
@@ -2965,28 +2974,23 @@ object Parsers {
29652974
*
29662975
* Param ::= id `:' ParamType [`=' Expr]
29672976
*
2977+
* The method here does not parse the outer `(...)` or any "head" modifiers
2978+
* in `erased`, `using`, `given`; this has to be done in the caller.
29682979
* @return the list of parameter definitions
29692980
*/
2970-
def paramClause(nparams: Int, // number of parameters preceding this clause
2981+
def paramClause(hmods: Modifiers, // parsed modifiers at start of clause
2982+
nparams: Int = 0, // number of parameters preceding this clause
29712983
ofClass: Boolean = false, // owner is a class
29722984
ofCaseClass: Boolean = false, // owner is a case class
29732985
prefix: Boolean = false, // clause precedes name of an extension method
29742986
givenOnly: Boolean = false, // only given parameters allowed
29752987
firstClause: Boolean = false // clause is the first in regular list of clauses
2976-
): List[ValDef] = {
2977-
var impliedMods: Modifiers = EmptyModifiers
2978-
2979-
def addParamMod(mod: () => Mod) = impliedMods = addMod(impliedMods, atSpan(in.skipToken()) { mod() })
2980-
2981-
def paramMods() =
2982-
if in.token == IMPLICIT then addParamMod(() => Mod.Implicit())
2983-
else
2984-
if isIdent(nme.using) then addParamMod(() => Mod.Given())
2985-
if in.token == ERASED then addParamMod(() => Mod.Erased())
2988+
): List[ValDef] =
2989+
var headMods: Modifiers = hmods
29862990

29872991
def param(): ValDef = {
29882992
val start = in.offset
2989-
var mods = impliedMods.withAnnotations(annotations())
2993+
var mods = headMods.withAnnotations(annotations())
29902994
if (ofClass) {
29912995
mods = addFlag(modifiers(start = mods), ParamAccessor)
29922996
mods =
@@ -2997,7 +3001,7 @@ object Parsers {
29973001
val mod = atSpan(in.skipToken()) { Mod.Var() }
29983002
addMod(mods, mod)
29993003
else
3000-
if (!(mods.flags &~ (ParamAccessor | Inline | impliedMods.flags)).isEmpty)
3004+
if (!(mods.flags &~ (ParamAccessor | Inline | headMods.flags)).isEmpty)
30013005
syntaxError("`val` or `var` expected")
30023006
if (firstClause && ofCaseClass) mods
30033007
else mods | PrivateLocal
@@ -3016,8 +3020,8 @@ object Parsers {
30163020
val default =
30173021
if (in.token == EQUALS) { in.nextToken(); subExpr() }
30183022
else EmptyTree
3019-
if (impliedMods.mods.nonEmpty)
3020-
impliedMods = impliedMods.withMods(Nil) // keep only flags, so that parameter positions don't overlap
3023+
if (headMods.mods.nonEmpty)
3024+
headMods = headMods.withMods(Nil) // keep only flags, so that parameter positions don't overlap
30213025
ValDef(name, tpt, default).withMods(mods)
30223026
}
30233027
}
@@ -3034,26 +3038,21 @@ object Parsers {
30343038
checkVarArgsRules(rest)
30353039
}
30363040

3037-
// begin paramClause
3038-
inParens {
3039-
if in.token == RPAREN && !prefix && !impliedMods.is(Given) then Nil
3040-
else
3041-
val clause =
3042-
if prefix then param() :: Nil
3041+
if in.token == RPAREN && !prefix && headMods.flags.isEmpty then
3042+
Nil
3043+
else
3044+
val clause =
3045+
if prefix then param() :: Nil
3046+
else
3047+
if givenOnly && !headMods.is(Given) then
3048+
syntaxError("`using` expected")
3049+
if !headMods.is(Given) || followingIsParam() then
3050+
commaSeparated(param)
30433051
else
3044-
paramMods()
3045-
if givenOnly && !impliedMods.is(Given) then
3046-
syntaxError("`using` expected")
3047-
val isParams =
3048-
!impliedMods.is(Given)
3049-
|| startParamTokens.contains(in.token)
3050-
|| isIdent && (in.name == nme.inline || in.lookahead.token == COLON)
3051-
if isParams then commaSeparated(() => param())
3052-
else contextTypes(ofClass, nparams)
3053-
checkVarArgsRules(clause)
3054-
clause
3055-
}
3056-
}
3052+
contextTypes(ofClass, nparams)
3053+
checkVarArgsRules(clause)
3054+
clause
3055+
end paramClause
30573056

30583057
/** ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
30593058
* DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’]
@@ -3067,13 +3066,22 @@ object Parsers {
30673066
def recur(firstClause: Boolean, nparams: Int): List[List[ValDef]] =
30683067
newLineOptWhenFollowedBy(LPAREN)
30693068
if in.token == LPAREN then
3070-
val paramsStart = in.offset
3071-
val params = paramClause(
3072-
nparams,
3073-
ofClass = ofClass,
3074-
ofCaseClass = ofCaseClass,
3075-
givenOnly = givenOnly,
3076-
firstClause = firstClause)
3069+
val params = inParens {
3070+
var headMods: Modifiers = EmptyModifiers
3071+
def addParamMod(mod: () => Mod) =
3072+
headMods = addMod(headMods, atSpan(in.skipToken()) { mod() })
3073+
if in.token == IMPLICIT then addParamMod(() => Mod.Implicit())
3074+
else
3075+
if isIdent(nme.using) then addParamMod(() => Mod.Given())
3076+
if in.token == ERASED then addParamMod(() => Mod.Erased())
3077+
paramClause(
3078+
headMods,
3079+
nparams,
3080+
ofClass = ofClass,
3081+
ofCaseClass = ofCaseClass,
3082+
givenOnly = givenOnly,
3083+
firstClause = firstClause)
3084+
}
30773085
val lastClause = params.nonEmpty && params.head.mods.flags.is(Implicit)
30783086
params :: (
30793087
if lastClause then Nil
@@ -3596,12 +3604,13 @@ object Parsers {
35963604
(Nil, constrAppsRest(constrAppRest(t), commaOK = true))
35973605
def givenHead(): (List[List[ValDef]], List[Tree]) =
35983606
if in.token == LPAREN then
3599-
afterArguments(givenHeadFinish, givenHeadRest)
3607+
maybeParams(paramClause(_), givenHeadFinish, givenHeadRest)
36003608
else
36013609
val constr = constrOrSimpleType()
36023610
if in.token == ARROW then givenHeadRest(constr :: Nil, EmptyModifiers)
36033611
else givenHeadFinish(constr)
36043612
val (vparamss, parents) = givenHead()
3613+
newLinesOptWhenFollowedBy(nme.as)
36053614
val name =
36063615
if in.isIdent(nme.as) then
36073616
in.nextToken()
@@ -3637,7 +3646,7 @@ object Parsers {
36373646
def extension(): ExtMethods =
36383647
val start = in.skipToken()
36393648
val tparams = typeParamClauseOpt(ParamOwner.Def)
3640-
val extParams = paramClause(0, prefix = true)
3649+
val extParams = inParens(paramClause(EmptyModifiers, prefix = true))
36413650
val givenParamss = paramClauses(givenOnly = true)
36423651
in.observeColonEOL()
36433652
if (in.token == COLONEOL) in.nextToken()

docs/docs/internals/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ FunArgType ::= Type
176176
| ‘=>’ Type PrefixOp(=>, t)
177177
ParamType ::= [‘=>’] ParamValueType
178178
ParamValueType ::= Type [‘*’] PostfixOp(t, "*")
179-
TypeArgs ::= ‘[’ Types ‘]’ ts
179+
TypeArgs ::= ‘[’ Types ‘]’ ts
180180
Refinement ::= ‘{’ [RefineDcl] {semi [RefineDcl]} ‘}’ ds
181181
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi)
182182
TypeParamBounds ::= TypeBounds {‘:’ Type} ContextBounds(typeBounds, tps)

tests/neg/functiontypes.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type T = (=> Int) => Int
2+
type U = (x: => Int) => Int // error, named parameter cannot be cbn since cbn dependent function types are not allowed.
3+
type V = _ => Int
4+
type W = (_) => Boolean

tests/run/implied-priority.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ object HigherPriority {
134134
}
135135

136136
object fallback5 {
137-
given [T](using ev: E[T] = new E[T]("fallback")) as (E[T] & HigherPriority.Type) = HigherPriority.inject(ev)
137+
given [T] => (ev: E[T] = new E[T]("fallback")) => (E[T] & HigherPriority.Type) = HigherPriority.inject(ev)
138138
}
139139

140140
def test5 = {

0 commit comments

Comments
 (0)