Skip to content

Commit 445badd

Browse files
committed
Support given => T syntax for uncached givens
1 parent 29ac088 commit 445badd

File tree

3 files changed

+47
-28
lines changed

3 files changed

+47
-28
lines changed

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

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3567,13 +3567,15 @@ object Parsers {
35673567
syntaxError(i"extension clause can only define methods", stat.span)
35683568
}
35693569

3570-
/** GivenDef ::= [GivenParams] Type ['as' id] ‘=’ Expr
3570+
/** GivenDef ::= [GivenParams | `=>`] Type ['as' id] ‘=’ Expr
35713571
* | [GivenParams] ConstrApps ['as' id] [TemplateBody]
3572-
* GivenParams ::= [DefTypeParamClause '=>'] {FunArgTypes '=>'}
3572+
* GivenParams ::= [DefTypeParamClause '=>'] {GivenParamClause '=>'}
3573+
* GivenParamClause ::= `(` DefParams `)` | FunArgTypes
35733574
*/
35743575
def givenDef(start: Offset, mods: Modifiers, givenMod: Mod) = atSpan(start, nameStart) {
35753576
var mods1 = addMod(mods, givenMod)
35763577
val start = in.offset
3578+
var defOnly = false
35773579
val (name, tparams, vparamss, parents) = if followingIsGivenSig() then
35783580
val name = if isIdent then ident() else EmptyTermName
35793581
val tparams = typeParamClauseOpt(ParamOwner.Def)
@@ -3588,28 +3590,35 @@ object Parsers {
35883590
(name, tparams, vparamss, parents)
35893591
else if true then
35903592
val tparams = typeParamClauseOpt(ParamOwner.Def)
3591-
if tparams.nonEmpty then accept(ARROW)
3592-
var counter = 0
3593-
def nextIdx = { counter += 1; counter }
3594-
def givenHeadRest(params: List[Tree], mods: Modifiers): (List[List[ValDef]], List[Tree]) =
3595-
accept(ARROW)
3596-
val vparams = params match
3597-
case (_: ValDef) :: _ =>
3598-
params.asInstanceOf[List[ValDef]].map(_.withFlags(Param | Given))
3599-
case _ =>
3600-
params.map(makeSyntheticParameter(nextIdx, _, Param | Synthetic | Given))
3601-
val (vparamss1, parents) = givenHead()
3602-
(vparams :: vparamss1, parents)
3603-
def givenHeadFinish(t: Tree): (List[List[ValDef]], List[Tree]) =
3604-
(Nil, constrAppsRest(constrAppRest(t), commaOK = true))
3605-
def givenHead(): (List[List[ValDef]], List[Tree]) =
3606-
if in.token == LPAREN then
3607-
maybeParams(paramClause(_), givenHeadFinish, givenHeadRest)
3593+
val (vparamss, parents) =
3594+
if tparams.isEmpty && in.token == ARROW then
3595+
defOnly = true
3596+
in.nextToken()
3597+
(Nil, constrApps(commaOK = true))
36083598
else
3609-
val constr = constrOrSimpleType()
3610-
if in.token == ARROW then givenHeadRest(constr :: Nil, EmptyModifiers)
3611-
else givenHeadFinish(constr)
3612-
val (vparamss, parents) = givenHead()
3599+
if tparams.nonEmpty then accept(ARROW)
3600+
var counter = 0
3601+
def nextIdx = { counter += 1; counter }
3602+
def givenHeadRest(params: List[Tree], mods: Modifiers): (List[List[ValDef]], List[Tree]) =
3603+
accept(ARROW)
3604+
val vparams = params match
3605+
case (_: ValDef) :: _ =>
3606+
params.asInstanceOf[List[ValDef]].map(_.withFlags(Param | Given))
3607+
case _ =>
3608+
params.map(makeSyntheticParameter(nextIdx, _, Param | Synthetic | Given))
3609+
val (vparamss1, parents) = givenHead()
3610+
(vparams :: vparamss1, parents)
3611+
def givenHeadFinish(t: Tree): (List[List[ValDef]], List[Tree]) =
3612+
(Nil, constrAppsRest(constrAppRest(t), commaOK = true))
3613+
def givenHead(): (List[List[ValDef]], List[Tree]) =
3614+
if in.token == LPAREN then
3615+
maybeParams(paramClause(_), givenHeadFinish, givenHeadRest)
3616+
else
3617+
val constr = constrOrSimpleType()
3618+
if in.token == ARROW then givenHeadRest(constr :: Nil, EmptyModifiers)
3619+
else givenHeadFinish(constr)
3620+
givenHead()
3621+
end if
36133622
newLinesOptWhenFollowedBy(nme.as)
36143623
val name =
36153624
if in.isIdent(nme.as) then
@@ -3620,10 +3629,12 @@ object Parsers {
36203629
else
36213630
(EmptyTermName, Nil, Nil, constrApps(commaOK = true))
36223631
val gdef =
3623-
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
3632+
if defOnly || in.token == EQUALS then
3633+
if parents.length != 1 || !parents.head.isType then
3634+
syntaxError(em"Given parent is not a type. It cannot be defined with an alias")
36243635
accept(EQUALS)
36253636
mods1 |= Final
3626-
if tparams.isEmpty && vparamss.isEmpty && !mods.is(Inline) then
3637+
if tparams.isEmpty && vparamss.isEmpty && !mods.is(Inline) && !defOnly then
36273638
mods1 |= Lazy
36283639
ValDef(name, parents.head, subExpr())
36293640
else

docs/docs/internals/syntax.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,9 +396,10 @@ ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses
396396
ConstrMods ::= {Annotation} [AccessModifier]
397397
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
398398
EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template)
399-
GivenDef ::= [GivenSig] Type ‘=’ Expr
400-
| [GivenSig] ConstrApps [TemplateBody]
401-
GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘as’ -- one of `id`, `DefParamClause`, `UsingParamClause` must appear
399+
GivenDef ::= [GivenParams | `=>`] Type ['as' id] ‘=’ Expr
400+
| [GivenParams] ConstrApps ['as' id] [TemplateBody]
401+
GivenParams ::= [DefTypeParamClause '=>'] {GivenParamClause '=>'}
402+
GivenParamClause ::= `(` DefParams `)` | FunArgTypes
402403
Extension ::= ‘extension’ [DefTypeParamClause] ‘(’ DefParam ‘)’
403404
{UsingParamClause}] ExtMethods
404405
ExtMethods ::= ExtMethod | [nl] ‘{’ ExtMethod {semi ExtMethod ‘}’

tests/run/given-mutable.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
var x = 0
2+
given => Int =
3+
x += 1
4+
x
5+
@main def Test =
6+
assert(summon[Int] == 1)
7+
assert(summon[Int] == 2)

0 commit comments

Comments
 (0)