@@ -901,6 +901,7 @@ object Parsers {
901
901
902
902
/** Are the next tokens a prefix of a formal parameter or given type?
903
903
* @pre: current token is LPAREN
904
+ * TODO: Drop once syntax has stabilized
904
905
*/
905
906
def followingIsParamOrGivenType () =
906
907
val lookahead = in.LookaheadScanner ()
@@ -915,6 +916,22 @@ object Parsers {
915
916
else false
916
917
else false
917
918
919
+ /** Are the next tokens a prefix of a formal parameter?
920
+ * @pre: current token is LPAREN
921
+ */
922
+ def followingIsParam () =
923
+ val lookahead = in.LookaheadScanner ()
924
+ lookahead.nextToken()
925
+ if startParamTokens.contains(lookahead.token) then true
926
+ else if lookahead.token == IDENTIFIER then
927
+ if lookahead.name == nme.inline then
928
+ lookahead.nextToken()
929
+ if lookahead.token == IDENTIFIER then
930
+ lookahead.nextToken()
931
+ lookahead.token == COLON
932
+ else false
933
+ else false
934
+
918
935
/** Are the next token the "GivenSig" part of a given definition,
919
936
* i.e. an identifier followed by type and value parameters, followed by `:`?
920
937
* @pre The current token is an identifier
@@ -2766,15 +2783,20 @@ object Parsers {
2766
2783
def typeParamClauseOpt (ownerKind : ParamOwner .Value ): List [TypeDef ] =
2767
2784
if (in.token == LBRACKET ) typeParamClause(ownerKind) else Nil
2768
2785
2769
- /** OLD: GivenTypes ::= AnnotType {‘,’ AnnotType}
2770
- * NEW: GivenTypes ::= Type {‘,’ Type}
2771
- */
2772
- def givenTypes (nparams : Int , ofClass : Boolean ): List [ValDef ] =
2773
- val tps = commaSeparated(typ)
2786
+ def typesToGivenParams (tps : List [Tree ], ofClass : Boolean , nparams : Int ): List [ValDef ] =
2774
2787
var counter = nparams
2775
2788
def nextIdx = { counter += 1 ; counter }
2776
2789
val paramFlags = if ofClass then Private | Local | ParamAccessor else Param
2777
- tps.map(makeSyntheticParameter(nextIdx, _, paramFlags | Synthetic | Given ))
2790
+ val tps1 = tps match
2791
+ case Tuple (tps1) :: Nil => tps1
2792
+ case _ => tps
2793
+ tps1.map(makeSyntheticParameter(nextIdx, _, paramFlags | Synthetic | Given ))
2794
+
2795
+ /** OLD: GivenTypes ::= AnnotType {‘,’ AnnotType}
2796
+ * NEW: GivenTypes ::= Type {‘,’ Type}
2797
+ */
2798
+ def givenTypes (ofClass : Boolean , nparams : Int ): List [ValDef ] =
2799
+ typesToGivenParams(commaSeparated(typ), ofClass, nparams)
2778
2800
2779
2801
/** ClsParamClause ::= ‘(’ [‘erased’] ClsParams ‘)’
2780
2802
* GivenClsParamClause::= ‘(’ ‘given’ [‘erased’] (ClsParams | GivenTypes) ‘)’
@@ -2873,7 +2895,7 @@ object Parsers {
2873
2895
|| startParamTokens.contains(in.token)
2874
2896
|| isIdent && (in.name == nme.inline || in.lookaheadIn(BitSet (COLON )))
2875
2897
if isParams then commaSeparated(() => param())
2876
- else givenTypes(nparams, ofClass )
2898
+ else givenTypes(ofClass, nparams )
2877
2899
checkVarArgsRules(clause)
2878
2900
clause
2879
2901
}
@@ -3384,12 +3406,13 @@ object Parsers {
3384
3406
syntaxError(i " extension clause can only define methods " , stat.span)
3385
3407
}
3386
3408
3387
- /** GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr
3388
- * | [GivenSig ‘:’] ConstrApps [[‘with’] TemplateBody]
3409
+ /** GivenDef ::= [GivenSig (‘:’ | <:)] {FunArgTypes ‘=>’} AnnotType ‘=’ Expr
3410
+ * | [GivenSig ‘:’] {FunArgTypes ‘=>’} ConstrApps [[‘with’] TemplateBody]
3389
3411
* | [id ‘:’] ExtParamClause {GivenParamClause} ‘extended’ ‘with’ ExtMethods
3390
3412
* GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause}
3391
3413
* ExtParamClause ::= [DefTypeParamClause] DefParamClause
3392
3414
* ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
3415
+ * TODO: cleanup once syntax has stabilized
3393
3416
*/
3394
3417
def givenDef (start : Offset , mods : Modifiers , instanceMod : Mod ) = atSpan(start, nameStart) {
3395
3418
var mods1 = addMod(mods, instanceMod)
@@ -3414,13 +3437,18 @@ object Parsers {
3414
3437
templ.body.foreach(checkExtensionMethod(tparams, _))
3415
3438
ModuleDef (name, templ)
3416
3439
else
3417
- val hasLabel = ! name.isEmpty && in.token == COLON
3418
- if hasLabel then in.nextToken()
3440
+ var hasLabel = false
3441
+ def skipColon () =
3442
+ if ! hasLabel && in.token == COLON then
3443
+ hasLabel = true
3444
+ in.nextToken()
3445
+ if ! name.isEmpty then skipColon()
3419
3446
val tparams = typeParamClauseOpt(ParamOwner .Def )
3447
+ if ! tparams.isEmpty then skipColon()
3420
3448
val paramsStart = in.offset
3421
- val vparamss =
3449
+ var vparamss =
3422
3450
if in.token == LPAREN && followingIsParamOrGivenType()
3423
- then paramClauses()
3451
+ then paramClauses() // todo: ONLY admit a single paramClause
3424
3452
else Nil
3425
3453
val isExtension = isIdent(nme.extended)
3426
3454
def checkAllGivens (vparamss : List [List [ValDef ]], what : String ) =
@@ -3440,19 +3468,45 @@ object Parsers {
3440
3468
stats.foreach(checkExtensionMethod(tparams, _))
3441
3469
ModuleDef (name, Template (makeConstructor(tparams, vparamss), Nil , Nil , self, stats))
3442
3470
else
3443
- checkAllGivens(vparamss, " parameter of given instance" )
3471
+ def makeGiven (params : List [ValDef ]): List [ValDef ] =
3472
+ params.map(param => param.withMods(param.mods | Given ))
3473
+ def conditionalParents (): List [Tree ] =
3474
+ accept(ARROW )
3475
+ if in.token == LPAREN && followingIsParam() then
3476
+ vparamss = vparamss :+ makeGiven(paramClause(vparamss.flatten.length))
3477
+ conditionalParents()
3478
+ else
3479
+ val constrs = constrApps(commaOK = true , templateCanFollow = true )
3480
+ if in.token == ARROW && constrs.forall(_.isType) then
3481
+ vparamss = vparamss
3482
+ :+ typesToGivenParams(constrs, ofClass = false , vparamss.flatten.length)
3483
+ conditionalParents()
3484
+ else constrs
3485
+
3486
+ val isConditional =
3487
+ in.token == ARROW
3488
+ && vparamss.length == 1
3489
+ && (hasLabel || name.isEmpty && tparams.isEmpty)
3490
+ if ! isConditional then checkAllGivens(vparamss, " parameter of given instance" )
3444
3491
val parents =
3445
- if hasLabel then
3446
- constrApps(commaOK = true , templateCanFollow = true )
3447
- else if in.token == SUBTYPE then
3492
+ if in.token == SUBTYPE && ! hasLabel then
3448
3493
if ! mods.is(Inline ) then
3449
3494
syntaxError(" `<:` is only allowed for given with `inline` modifier" )
3450
3495
in.nextToken()
3451
- TypeBoundsTree (EmptyTree , toplevelTyp()) :: Nil
3496
+ TypeBoundsTree (EmptyTree , annotType()) :: Nil
3497
+ else if isConditional then
3498
+ vparamss = vparamss.map(makeGiven)
3499
+ conditionalParents()
3452
3500
else
3453
- if ! (name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
3501
+ if ! hasLabel && ! (name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
3454
3502
accept(COLON )
3455
- constrApps(commaOK = true , templateCanFollow = true )
3503
+ val constrs = constrApps(commaOK = true , templateCanFollow = true )
3504
+ if in.token == ARROW && vparamss.isEmpty && constrs.forall(_.isType) then
3505
+ vparamss = typesToGivenParams(constrs, ofClass = false , 0 ) :: Nil
3506
+ conditionalParents()
3507
+ else
3508
+ constrs
3509
+
3456
3510
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
3457
3511
in.nextToken()
3458
3512
mods1 |= Final
0 commit comments