@@ -901,6 +901,7 @@ object Parsers {
901901
902902 /** Are the next tokens a prefix of a formal parameter or given type?
903903 * @pre: current token is LPAREN
904+ * TODO: Drop once syntax has stabilized
904905 */
905906 def followingIsParamOrGivenType () =
906907 val lookahead = in.LookaheadScanner ()
@@ -915,6 +916,22 @@ object Parsers {
915916 else false
916917 else false
917918
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+
918935 /** Are the next token the "GivenSig" part of a given definition,
919936 * i.e. an identifier followed by type and value parameters, followed by `:`?
920937 * @pre The current token is an identifier
@@ -2766,15 +2783,20 @@ object Parsers {
27662783 def typeParamClauseOpt (ownerKind : ParamOwner .Value ): List [TypeDef ] =
27672784 if (in.token == LBRACKET ) typeParamClause(ownerKind) else Nil
27682785
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 ] =
27742787 var counter = nparams
27752788 def nextIdx = { counter += 1 ; counter }
27762789 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)
27782800
27792801 /** ClsParamClause ::= ‘(’ [‘erased’] ClsParams ‘)’
27802802 * GivenClsParamClause::= ‘(’ ‘given’ [‘erased’] (ClsParams | GivenTypes) ‘)’
@@ -2873,7 +2895,7 @@ object Parsers {
28732895 || startParamTokens.contains(in.token)
28742896 || isIdent && (in.name == nme.inline || in.lookaheadIn(BitSet (COLON )))
28752897 if isParams then commaSeparated(() => param())
2876- else givenTypes(nparams, ofClass )
2898+ else givenTypes(ofClass, nparams )
28772899 checkVarArgsRules(clause)
28782900 clause
28792901 }
@@ -3384,12 +3406,13 @@ object Parsers {
33843406 syntaxError(i " extension clause can only define methods " , stat.span)
33853407 }
33863408
3387- /** GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr
3388- * | [GivenSig ‘:’] ConstrApps [[‘with’] TemplateBody]
3409+ /** GivenDef ::= [GivenSig (‘:’ | <:)] {FunArgTypes ‘=>’} AnnotType ‘=’ Expr
3410+ * | [GivenSig ‘:’] {FunArgTypes ‘=>’} ConstrApps [[‘with’] TemplateBody]
33893411 * | [id ‘:’] ExtParamClause {GivenParamClause} ‘extended’ ‘with’ ExtMethods
33903412 * GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause}
33913413 * ExtParamClause ::= [DefTypeParamClause] DefParamClause
33923414 * ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
3415+ * TODO: cleanup once syntax has stabilized
33933416 */
33943417 def givenDef (start : Offset , mods : Modifiers , instanceMod : Mod ) = atSpan(start, nameStart) {
33953418 var mods1 = addMod(mods, instanceMod)
@@ -3414,13 +3437,18 @@ object Parsers {
34143437 templ.body.foreach(checkExtensionMethod(tparams, _))
34153438 ModuleDef (name, templ)
34163439 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()
34193446 val tparams = typeParamClauseOpt(ParamOwner .Def )
3447+ if ! tparams.isEmpty then skipColon()
34203448 val paramsStart = in.offset
3421- val vparamss =
3449+ var vparamss =
34223450 if in.token == LPAREN && followingIsParamOrGivenType()
3423- then paramClauses()
3451+ then paramClauses() // todo: ONLY admit a single paramClause
34243452 else Nil
34253453 val isExtension = isIdent(nme.extended)
34263454 def checkAllGivens (vparamss : List [List [ValDef ]], what : String ) =
@@ -3440,19 +3468,45 @@ object Parsers {
34403468 stats.foreach(checkExtensionMethod(tparams, _))
34413469 ModuleDef (name, Template (makeConstructor(tparams, vparamss), Nil , Nil , self, stats))
34423470 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" )
34443491 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
34483493 if ! mods.is(Inline ) then
34493494 syntaxError(" `<:` is only allowed for given with `inline` modifier" )
34503495 in.nextToken()
3451- TypeBoundsTree (EmptyTree , toplevelTyp()) :: Nil
3496+ TypeBoundsTree (EmptyTree , annotType()) :: Nil
3497+ else if isConditional then
3498+ vparamss = vparamss.map(makeGiven)
3499+ conditionalParents()
34523500 else
3453- if ! (name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
3501+ if ! hasLabel && ! (name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
34543502 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+
34563510 if in.token == EQUALS && parents.length == 1 && parents.head.isType then
34573511 in.nextToken()
34583512 mods1 |= Final
0 commit comments