@@ -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,16 +2783,18 @@ 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
27772790 tps.map(makeSyntheticParameter(nextIdx, _, paramFlags | Synthetic | Given ))
27782791
2792+ /** OLD: GivenTypes ::= AnnotType {‘,’ AnnotType}
2793+ * NEW: GivenTypes ::= Type {‘,’ Type}
2794+ */
2795+ def givenTypes (ofClass : Boolean , nparams : Int ): List [ValDef ] =
2796+ typesToGivenParams(commaSeparated(typ), ofClass, nparams)
2797+
27792798 /** ClsParamClause ::= ‘(’ [‘erased’] ClsParams ‘)’
27802799 * GivenClsParamClause::= ‘(’ ‘given’ [‘erased’] (ClsParams | GivenTypes) ‘)’
27812800 * ClsParams ::= ClsParam {‘,’ ClsParam}
@@ -2873,7 +2892,7 @@ object Parsers {
28732892 || startParamTokens.contains(in.token)
28742893 || isIdent && (in.name == nme.inline || in.lookaheadIn(BitSet (COLON )))
28752894 if isParams then commaSeparated(() => param())
2876- else givenTypes(nparams, ofClass )
2895+ else givenTypes(ofClass, nparams )
28772896 checkVarArgsRules(clause)
28782897 clause
28792898 }
@@ -3384,12 +3403,13 @@ object Parsers {
33843403 syntaxError(i " extension clause can only define methods " , stat.span)
33853404 }
33863405
3387- /** GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr
3388- * | [GivenSig ‘:’] ConstrApps [[‘with’] TemplateBody]
3406+ /** GivenDef ::= [GivenSig (‘:’ | <:)] {FunArgTypes ‘=>’} AnnotType ‘=’ Expr
3407+ * | [GivenSig ‘:’] {FunArgTypes ‘=>’} ConstrApps [[‘with’] TemplateBody]
33893408 * | [id ‘:’] ExtParamClause {GivenParamClause} ‘extended’ ‘with’ ExtMethods
33903409 * GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause}
33913410 * ExtParamClause ::= [DefTypeParamClause] DefParamClause
33923411 * ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
3412+ * TODO: cleanup once syntax has stabilized
33933413 */
33943414 def givenDef (start : Offset , mods : Modifiers , instanceMod : Mod ) = atSpan(start, nameStart) {
33953415 var mods1 = addMod(mods, instanceMod)
@@ -3414,13 +3434,18 @@ object Parsers {
34143434 templ.body.foreach(checkExtensionMethod(tparams, _))
34153435 ModuleDef (name, templ)
34163436 else
3417- val hasLabel = ! name.isEmpty && in.token == COLON
3418- if hasLabel then in.nextToken()
3437+ var hasLabel = false
3438+ def skipColon () =
3439+ if ! hasLabel && in.token == COLON then
3440+ hasLabel = true
3441+ in.nextToken()
3442+ if ! name.isEmpty then skipColon()
34193443 val tparams = typeParamClauseOpt(ParamOwner .Def )
3444+ if ! tparams.isEmpty then skipColon()
34203445 val paramsStart = in.offset
3421- val vparamss =
3446+ var vparamss =
34223447 if in.token == LPAREN && followingIsParamOrGivenType()
3423- then paramClauses()
3448+ then paramClauses() // todo: ONLY admit a single paramClause
34243449 else Nil
34253450 val isExtension = isIdent(nme.extended)
34263451 def checkAllGivens (vparamss : List [List [ValDef ]], what : String ) =
@@ -3440,19 +3465,43 @@ object Parsers {
34403465 stats.foreach(checkExtensionMethod(tparams, _))
34413466 ModuleDef (name, Template (makeConstructor(tparams, vparamss), Nil , Nil , self, stats))
34423467 else
3443- checkAllGivens(vparamss, " parameter of given instance" )
3468+ def conditionalParents (): List [Tree ] =
3469+ accept(ARROW )
3470+ if in.token == LPAREN && followingIsParam() then
3471+ vparamss = vparamss :+ paramClause(vparamss.flatten.length)
3472+ conditionalParents()
3473+ else
3474+ val constrs = constrApps(commaOK = true , templateCanFollow = true )
3475+ if in.token == ARROW && constrs.forall(_.isType) then
3476+ vparamss = vparamss
3477+ :+ typesToGivenParams(constrs, ofClass = false , vparamss.flatten.length)
3478+ conditionalParents()
3479+ else constrs
3480+
3481+ val isConditional =
3482+ in.token == ARROW
3483+ && vparamss.length == 1
3484+ && (hasLabel || name.isEmpty && tparams.isEmpty)
3485+ if ! isConditional then checkAllGivens(vparamss, " parameter of given instance" )
34443486 val parents =
3445- if hasLabel then
3446- constrApps(commaOK = true , templateCanFollow = true )
3447- else if in.token == SUBTYPE then
3487+ if in.token == SUBTYPE && ! hasLabel then
34483488 if ! mods.is(Inline ) then
34493489 syntaxError(" `<:` is only allowed for given with `inline` modifier" )
34503490 in.nextToken()
3451- TypeBoundsTree (EmptyTree , toplevelTyp()) :: Nil
3491+ TypeBoundsTree (EmptyTree , annotType()) :: Nil
3492+ else if isConditional then
3493+ vparamss = vparamss.head.map(param => param.withMods(param.mods | Given )) :: Nil
3494+ conditionalParents()
34523495 else
3453- if ! (name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
3496+ if ! hasLabel && ! (name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then
34543497 accept(COLON )
3455- constrApps(commaOK = true , templateCanFollow = true )
3498+ val constrs = constrApps(commaOK = true , templateCanFollow = true )
3499+ if in.token == ARROW && vparamss.isEmpty && constrs.forall(_.isType) then
3500+ vparamss = typesToGivenParams(constrs, ofClass = false , 0 ) :: Nil
3501+ conditionalParents()
3502+ else
3503+ constrs
3504+
34563505 if in.token == EQUALS && parents.length == 1 && parents.head.isType then
34573506 in.nextToken()
34583507 mods1 |= Final
0 commit comments