Skip to content

Commit c2478a3

Browse files
authored
Merge pull request #8162 from dotty-staging/change-given-using
Change to given/using syntax
2 parents c4c847f + 0861a29 commit c2478a3

File tree

513 files changed

+1213
-1308
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

513 files changed

+1213
-1308
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

+1
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,7 @@ object StdNames {
601601
val universe: N = "universe"
602602
val update: N = "update"
603603
val updateDynamic: N = "updateDynamic"
604+
val using: N = "using"
604605
val value: N = "value"
605606
val valueOf : N = "valueOf"
606607
val values: N = "values"

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

+36-78
Original file line numberDiff line numberDiff line change
@@ -911,11 +911,14 @@ object Parsers {
911911

912912
/** Are the next tokens a prefix of a formal parameter or given type?
913913
* @pre: current token is LPAREN
914+
* TODO: Drop once syntax has stabilized
914915
*/
915916
def followingIsParamOrGivenType() =
916917
val lookahead = in.LookaheadScanner()
917918
lookahead.nextToken()
918-
if startParamOrGivenTypeTokens.contains(lookahead.token) then true
919+
if startParamOrGivenTypeTokens.contains(lookahead.token)
920+
|| lookahead.isIdent(nme.using)
921+
then true
919922
else if lookahead.token == IDENTIFIER then
920923
if lookahead.name == nme.inline then
921924
lookahead.nextToken()
@@ -944,7 +947,6 @@ object Parsers {
944947
else
945948
lookahead.token == SUBTYPE // TODO: remove
946949
|| lookahead.isIdent(nme.as)
947-
|| lookahead.token == WITH && lookahead.ch != Chars.LF // TODO: remove LF test
948950

949951
def followingIsExtension() =
950952
val lookahead = in.LookaheadScanner()
@@ -1344,8 +1346,8 @@ object Parsers {
13441346
* MonoFunType ::= FunArgTypes (‘=>’ | ‘?=>’) Type
13451347
* PolyFunType ::= HKTypeParamClause '=>' Type
13461348
* FunArgTypes ::= InfixType
1347-
* | `(' [ [ ‘['erased'] FunArgType {`,' FunArgType } ] `)'
1348-
* | '(' [ ‘['erased'] TypedFunParam {',' TypedFunParam } ')'
1349+
* | `(' [ [ ‘[using]’ ‘['erased'] FunArgType {`,' FunArgType } ] `)'
1350+
* | '(' [ ‘[using]’ ‘['erased'] TypedFunParam {',' TypedFunParam } ')'
13491351
*/
13501352
def typ(): Tree = {
13511353
val start = in.offset
@@ -2184,7 +2186,6 @@ object Parsers {
21842186
* | SimpleExpr `.' MatchClause
21852187
* | SimpleExpr (TypeArgs | NamedTypeArgs)
21862188
* | SimpleExpr1 ArgumentExprs
2187-
* | SimpleExpr ContextArguments
21882189
* Quoted ::= ‘'’ ‘{’ Block ‘}’
21892190
* | ‘'’ ‘[’ Type ‘]’
21902191
*/
@@ -2253,8 +2254,6 @@ object Parsers {
22532254
case DOT =>
22542255
in.nextToken()
22552256
simpleExprRest(selector(t), canApply = true)
2256-
case DOTWITH =>
2257-
simpleExprRest(contextArguments(t), canApply = true)
22582257
case LBRACKET =>
22592258
val tapp = atSpan(startOffset(t), in.offset) { TypeApply(t, typeArgs(namedOK = true, wildOK = false)) }
22602259
simpleExprRest(tapp, canApply = true)
@@ -2294,13 +2293,13 @@ object Parsers {
22942293
def exprsInParensOpt(): List[Tree] =
22952294
if (in.token == RPAREN) Nil else commaSeparated(exprInParens)
22962295

2297-
/** ParArgumentExprs ::= `(' [‘given’] [ExprsInParens] `)'
2296+
/** ParArgumentExprs ::= `(' [‘using’] [ExprsInParens] `)'
22982297
* | `(' [ExprsInParens `,'] PostfixExpr `:' `_' `*' ')'
22992298
*/
23002299
def parArgumentExprs(): (List[Tree], Boolean) = inParens {
23012300
if in.token == RPAREN then
23022301
(Nil, false)
2303-
else if in.token == GIVEN then
2302+
else if in.token == GIVEN || isIdent(nme.using) then
23042303
in.nextToken()
23052304
(commaSeparated(argumentExpr), true)
23062305
else
@@ -2331,7 +2330,7 @@ object Parsers {
23312330
else fn
23322331
}
23332332

2334-
/** ParArgumentExprss ::= {ParArgumentExprs | ContextArguments}
2333+
/** ParArgumentExprss ::= {ParArgumentExprs}
23352334
*
23362335
* Special treatment for arguments to primary constructor annotations.
23372336
* (...) is considered an argument only if it does not look like a formal
@@ -2356,8 +2355,6 @@ object Parsers {
23562355
parArgumentExprss(
23572356
atSpan(startOffset(fn)) { mkApply(fn, parArgumentExprs()) }
23582357
)
2359-
else if in.token == DOTWITH then
2360-
parArgumentExprss(contextArguments(fn))
23612358
else fn
23622359
}
23632360

@@ -2387,14 +2384,6 @@ object Parsers {
23872384
else Block(stats, EmptyTree)
23882385
}
23892386

2390-
/** ContextArguments ::= ‘.’ ‘with’ ArgumentExprs */
2391-
def contextArguments(t: Tree): Tree =
2392-
if in.token == DOTWITH then
2393-
atSpan(t.span.start, in.skipToken()) {
2394-
Apply(t, argumentExprs()._1).setGivenApply()
2395-
}
2396-
else t
2397-
23982387
/** Guard ::= if PostfixExpr
23992388
*/
24002389
def guard(): Tree =
@@ -2886,23 +2875,22 @@ object Parsers {
28862875
def typeParamClauseOpt(ownerKind: ParamOwner.Value): List[TypeDef] =
28872876
if (in.token == LBRACKET) typeParamClause(ownerKind) else Nil
28882877

2889-
/** AnnotTypes ::= AnnotType {‘,’ AnnotType}
2890-
* Types ::= Type {‘,’ Type}
2878+
/** ContextTypes ::= Type {‘,’ Type}
28912879
*/
2892-
def givenTypes(parseType: () => Tree, nparams: Int, ofClass: Boolean): List[ValDef] =
2893-
val tps = commaSeparated(parseType)
2880+
def contextTypes(ofClass: Boolean, nparams: Int): List[ValDef] =
2881+
val tps = commaSeparated(typ)
28942882
var counter = nparams
28952883
def nextIdx = { counter += 1; counter }
28962884
val paramFlags = if ofClass then Private | Local | ParamAccessor else Param
28972885
tps.map(makeSyntheticParameter(nextIdx, _, paramFlags | Synthetic | Given))
28982886

2899-
/** ClsParamClause ::= ‘(’ [‘erased’] ClsParams ‘)’
2900-
* GivenClsParamClause::= 'with' (‘(’ (ClsParams | Types) ‘)’ | AnnotTypes)
2887+
/** ClsParamClause ::= ‘(’ [‘erased’] ClsParams ‘)’ | UsingClsParamClause
2888+
* UsingClsParamClause::= ‘(’ ‘using’ [‘erased’] (ClsParams | ContextTypes) ‘)’
29012889
* ClsParams ::= ClsParam {‘,’ ClsParam}
29022890
* ClsParam ::= {Annotation}
29032891
*
2904-
* DefParamClause ::= ‘(’ [‘erased’] DefParams ‘)’
2905-
* GivenParamClause ::= ‘with’ (‘(’ (DefParams | Types) ‘)’ | AnnotTypes)
2892+
* DefParamClause ::= ‘(’ [‘erased’] DefParams ‘)’ | UsingParamClause
2893+
* UsingParamClause ::= ‘(’ ‘using’ [‘erased’] (DefParams | ContextTypes) ‘)’
29062894
* DefParams ::= DefParam {‘,’ DefParam}
29072895
* DefParam ::= {Annotation} [‘inline’] Param
29082896
*
@@ -2915,17 +2903,17 @@ object Parsers {
29152903
ofCaseClass: Boolean = false, // owner is a case class
29162904
prefix: Boolean = false, // clause precedes name of an extension method
29172905
givenOnly: Boolean = false, // only given parameters allowed
2918-
firstClause: Boolean = false, // clause is the first in regular list of clauses
2919-
prefixMods: Modifiers = EmptyModifiers // is `Given` if this is a with clause
2906+
firstClause: Boolean = false // clause is the first in regular list of clauses
29202907
): List[ValDef] = {
2921-
var impliedMods: Modifiers = prefixMods
2908+
var impliedMods: Modifiers = EmptyModifiers
29222909

2923-
def impliedModOpt(token: Token, mod: () => Mod): Boolean =
2924-
if in.token == token then
2925-
impliedMods = addMod(impliedMods, atSpan(in.skipToken()) { mod() })
2926-
true
2910+
def addParamMod(mod: () => Mod) = impliedMods = addMod(impliedMods, atSpan(in.skipToken()) { mod() })
2911+
2912+
def paramMods() =
2913+
if in.token == IMPLICIT then addParamMod(() => Mod.Implicit())
29272914
else
2928-
false
2915+
if in.token == GIVEN || isIdent(nme.using) then addParamMod(() => Mod.Given())
2916+
if in.token == ERASED then addParamMod(() => Mod.Erased())
29292917

29302918
def param(): ValDef = {
29312919
val start = in.offset
@@ -2984,32 +2972,22 @@ object Parsers {
29842972
val clause =
29852973
if prefix then param() :: Nil
29862974
else
2987-
if !impliedModOpt(IMPLICIT, () => Mod.Implicit()) then
2988-
impliedModOpt(GIVEN, () => Mod.Given())
2989-
impliedModOpt(ERASED, () => Mod.Erased())
2975+
paramMods()
29902976
if givenOnly && !impliedMods.is(Given) then
2991-
syntaxError("Normal parameter clause cannot follow context parameter clause")
2977+
syntaxError("`using` expected")
29922978
val isParams =
29932979
!impliedMods.is(Given)
29942980
|| startParamTokens.contains(in.token)
29952981
|| isIdent && (in.name == nme.inline || in.lookaheadIn(BitSet(COLON)))
29962982
if isParams then commaSeparated(() => param())
2997-
else givenTypes(typ, nparams, ofClass)
2983+
else contextTypes(ofClass, nparams)
29982984
checkVarArgsRules(clause)
29992985
clause
30002986
}
30012987
}
30022988

30032989
/** ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
3004-
* | ClsParamClause ClsParamClauses
3005-
* | ClsParamClauses1
3006-
* ClsParamClauses1 ::= WithClsParamClause ClsParamClauses
3007-
* | AnnotTypes ClsParamClauses1ClsParamClauses
30082990
* DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’]
3009-
* | DefParamClause DefParamClauses
3010-
* | DefParamClauses1
3011-
* DefParamClauses1 ::= WithCaramClause DefParamClauses
3012-
* | AnnotTypes DeParamClauses1
30132991
*
30142992
* @return The parameter definitions
30152993
*/
@@ -3019,33 +2997,18 @@ object Parsers {
30192997

30202998
def recur(firstClause: Boolean, nparams: Int): List[List[ValDef]] =
30212999
newLineOptWhenFollowedBy(LPAREN)
3022-
val prefixMods =
3023-
if in.token == WITH && in.ch != Chars.LF then // TODO: remove LF test
3024-
in.nextToken()
3025-
Modifiers(Given)
3026-
else
3027-
EmptyModifiers
30283000
if in.token == LPAREN then
30293001
val paramsStart = in.offset
30303002
val params = paramClause(
30313003
nparams,
30323004
ofClass = ofClass,
30333005
ofCaseClass = ofCaseClass,
30343006
givenOnly = givenOnly,
3035-
firstClause = firstClause,
3036-
prefixMods = prefixMods)
3007+
firstClause = firstClause)
30373008
val lastClause = params.nonEmpty && params.head.mods.flags.is(Implicit)
3038-
val isGivenClause = prefixMods.is(Given)
3039-
|| params.nonEmpty && params.head.mods.flags.is(Given)
30403009
params :: (
30413010
if lastClause then Nil
30423011
else recur(firstClause = false, nparams + params.length))
3043-
else if prefixMods.is(Given) then
3044-
val params = givenTypes(annotType, nparams, ofClass)
3045-
params :: (
3046-
if in.token == WITH then recur(firstClause = false, nparams + params.length)
3047-
else Nil
3048-
)
30493012
else Nil
30503013
end recur
30513014

@@ -3090,8 +3053,8 @@ object Parsers {
30903053

30913054
/** ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
30923055
* | WildCardSelector {‘,’ WildCardSelector}
3093-
* WildCardSelector ::= ‘given’ [InfixType]
3094-
* | ‘_' [‘:’ InfixType]
3056+
* WildCardSelector ::= ‘given’ (‘_' | InfixType)
3057+
* | ‘_'
30953058
*/
30963059
def importSelectors(idOK: Boolean): List[ImportSelector] =
30973060
val selToken = in.token
@@ -3543,10 +3506,7 @@ object Parsers {
35433506

35443507
/** GivenDef ::= [GivenSig] [‘_’ ‘<:’] Type ‘=’ Expr
35453508
* | [GivenSig] ConstrApps [TemplateBody]
3546-
* GivenSig ::= [id] [DefTypeParamClause] {WithParamsOrTypes} ‘as’
3547-
* ExtParamClause ::= [DefTypeParamClause] DefParamClause
3548-
* ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
3549-
* WithParamsOrTypes ::= WithParamClause | AnnotTypes
3509+
* GivenSig ::= [id] [DefTypeParamClause] {UsingParamClauses} ‘as’
35503510
*/
35513511
def givenDef(start: Offset, mods: Modifiers, instanceMod: Mod) = atSpan(start, nameStart) {
35523512
var mods1 = addMod(mods, instanceMod)
@@ -3571,18 +3531,17 @@ object Parsers {
35713531
templ.body.foreach(checkExtensionMethod(tparams, _))
35723532
ModuleDef(name, templ)
35733533
else
3574-
val hasLabel = !name.isEmpty && in.token == COLON || in.isIdent(nme.as)
3534+
val hasLabel = !name.isEmpty && in.token == COLON || isIdent(nme.as)
35753535
if hasLabel then in.nextToken()
35763536
val tparams = typeParamClauseOpt(ParamOwner.Def)
35773537
val paramsStart = in.offset
35783538
val vparamss =
3579-
if in.token == WITH && in.ch != Chars.LF // TODO: remove LF test
3580-
|| in.token == LPAREN && followingIsParamOrGivenType()
3539+
if in.token == LPAREN && followingIsParamOrGivenType()
35813540
then paramClauses()
35823541
else Nil
35833542
def checkAllGivens(vparamss: List[List[ValDef]], what: String) =
35843543
vparamss.foreach(_.foreach(vparam =>
3585-
if !vparam.mods.is(Given) then syntaxError(em"$what must be `given`", vparam.span)))
3544+
if !vparam.mods.is(Given) then syntaxError(em"$what must be preceded by `using`", vparam.span)))
35863545
checkAllGivens(vparamss, "parameter of given instance")
35873546
val parents =
35883547
if in.token == SUBTYPE && !hasLabel then
@@ -3620,7 +3579,7 @@ object Parsers {
36203579
finalizeDef(gdef, mods1, start)
36213580
}
36223581

3623-
/** ExtensionDef ::= [id] ‘on’ ExtParamClause GivenParamClauses ExtMethods
3582+
/** ExtensionDef ::= [id] ‘on’ ExtParamClause {UsingParamClause} ExtMethods
36243583
*/
36253584
def extensionDef(start: Offset, mods: Modifiers): ModuleDef =
36263585
in.nextToken()
@@ -3644,8 +3603,7 @@ object Parsers {
36443603
val constrApp: () => Tree = () => {
36453604
val t = rejectWildcardType(annotType(), fallbackTree = Ident(nme.ERROR))
36463605
// Using Ident(nme.ERROR) to avoid causing cascade errors on non-user-written code
3647-
if in.token == LPAREN || in.token == DOTWITH then parArgumentExprss(wrapNew(t))
3648-
else t
3606+
if in.token == LPAREN then parArgumentExprss(wrapNew(t)) else t
36493607
}
36503608

36513609
/** ConstrApps ::= ConstrApp {(‘,’ | ‘with’) ConstrApp}

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

+1-9
Original file line numberDiff line numberDiff line change
@@ -593,11 +593,7 @@ object Scanners {
593593
this.copyFrom(prev)
594594
}
595595

596-
/** - Join CASE + CLASS => CASECLASS,
597-
* CASE + OBJECT => CASEOBJECT,
598-
* SEMI + ELSE => ELSE,
599-
* COLON + <EOL> => COLONEOL
600-
* DOT + WITH => DOTWITH
596+
/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE, COLON + <EOL> => COLONEOL
601597
* - Insert missing OUTDENTs at EOF
602598
*/
603599
def postProcessToken(): Unit = {
@@ -623,10 +619,6 @@ object Scanners {
623619
} else if (token == EOF) { // e.g. when the REPL is parsing "val List(x, y, _*,"
624620
/* skip the trailing comma */
625621
} else reset()
626-
case DOT =>
627-
lookahead()
628-
if token == WITH then fuse(DOTWITH)
629-
else reset()
630622
case COLON =>
631623
if colonSyntax then observeColonEOL()
632624
case EOF | RBRACE =>

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

-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ object Tokens extends TokensCommon {
204204
final val QUOTE = 87; enter(QUOTE, "'")
205205

206206
final val COLONEOL = 88; enter(COLONEOL, ":", ": at eol")
207-
final val DOTWITH = 89; enter(DOTWITH, ".with")
208207

209208
/** XML mode */
210209
final val XMLSTART = 98; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
244244
case _ => toTextGlobal(args, ", ")
245245
}
246246
"[applied to ("
247-
~ keywordText("given ").provided(tp.isContextualMethod)
247+
~ keywordText("using ").provided(tp.isContextualMethod)
248248
~ keywordText("erased ").provided(tp.isErasedMethod)
249249
~ argsText
250250
~ ") returning "
@@ -389,8 +389,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
389389
keywordStr("${") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
390390
else
391391
toTextLocal(fun)
392-
~ ("." ~ keywordText("with")).provided(app.isGivenApply && !homogenizedView)
393392
~ "("
393+
~ Str("using ").provided(app.isGivenApply && !homogenizedView)
394394
~ toTextGlobal(args, ", ")
395395
~ ")"
396396
case tree: TypeApply =>

compiler/src/dotty/tools/dotc/typer/Typer.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -2663,9 +2663,9 @@ class Typer extends Namer
26632663
// coming from context bounds. Issue a warning instead and offer a patch.
26642664
ctx.migrationWarning(
26652665
em"""Context bounds will map to context parameters.
2666-
|A `with` clause is needed to pass explicit arguments to them.
2666+
|A `using` clause is needed to pass explicit arguments to them.
26672667
|This code can be rewritten automatically using -rewrite""", tree.sourcePos)
2668-
patch(Span(tree.span.end), ".with")
2668+
patch(Span(pt.args.head.span.start), "using ")
26692669
tree
26702670
else
26712671
adaptNoArgs(wtp) // insert arguments implicitly

0 commit comments

Comments
 (0)