Skip to content

Commit 8d4906f

Browse files
committed
Implement anonymous context parameters
1 parent e5cbc24 commit 8d4906f

File tree

6 files changed

+31
-18
lines changed

6 files changed

+31
-18
lines changed

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
404404
def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = EmptyModifiers)(implicit ctx: Context): ValDef =
405405
ValDef(pname, tpe, EmptyTree).withMods(mods | Param)
406406

407-
def makeSyntheticParameter(n: Int = 1, tpt: Tree = null)(implicit ctx: Context): ValDef =
407+
def makeSyntheticParameter(n: Int = 1, tpt: Tree = null, flags: FlagSet = EmptyFlags)(implicit ctx: Context): ValDef =
408408
ValDef(nme.syntheticParamName(n), if (tpt == null) TypeTree() else tpt, EmptyTree)
409-
.withFlags(SyntheticTermParam)
409+
.withFlags(flags | SyntheticTermParam)
410410

411411
def lambdaAbstract(tparams: List[TypeDef], tpt: Tree)(implicit ctx: Context): Tree =
412412
if (tparams.isEmpty) tpt else LambdaTypeTree(tparams, tpt)

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

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,7 +2037,9 @@ object Parsers {
20372037
/** ClsParamClause ::= [nl | ‘with’] `(' [FunArgMods] [ClsParams] ')'
20382038
* ClsParams ::= ClsParam {`' ClsParam}
20392039
* ClsParam ::= {Annotation} [{Modifier} (`val' | `var') | `inline'] Param
2040-
* DefParamClause ::= [nl | ‘with’] `(' [FunArgMods] [DefParams] ')'
2040+
* DefParamClause ::= [nl] `(' [FunArgMods] [DefParams] ')' | InstParamClause
2041+
* InstParamClause ::= ‘with’ (‘(’ [DefParams] ‘)’ | ContextTypes)
2042+
* ContextTypes ::= RefinedType {`,' RefinedType}
20412043
* DefParams ::= DefParam {`,' DefParam}
20422044
* DefParam ::= {Annotation} [`inline'] Param
20432045
* Param ::= id `:' ParamType [`=' Expr]
@@ -2128,33 +2130,42 @@ object Parsers {
21282130

21292131
/** ClsParamClauses ::= {ClsParamClause}
21302132
* DefParamClauses ::= {DefParamClause}
2133+
* InstParamClauses ::= {InstParamClause}
21312134
*
21322135
* @return The parameter definitions
21332136
*/
21342137
def paramClauses(ofClass: Boolean = false,
21352138
ofCaseClass: Boolean = false,
21362139
ofInstance: Boolean = false): List[List[ValDef]] = {
2137-
def recur(firstClause: Boolean): List[List[ValDef]] = {
2140+
def recur(firstClause: Boolean, nparams: Int): List[List[ValDef]] = {
21382141
val initialMods =
21392142
if (in.token == WITH) {
21402143
in.nextToken()
21412144
Modifiers(Contextual | Implicit)
21422145
}
21432146
else EmptyModifiers
2147+
val isContextual = initialMods.is(Contextual)
21442148
newLineOptWhenFollowedBy(LPAREN)
2145-
if (initialMods.is(Contextual) || in.token == LPAREN && !ofInstance) {
2149+
if (in.token == LPAREN) {
2150+
if (ofInstance && !isContextual)
2151+
syntaxError(em"parameters of instance definitions must come after `with'")
21462152
val params = paramClause(
21472153
ofClass = ofClass,
21482154
ofCaseClass = ofCaseClass,
21492155
firstClause = firstClause,
21502156
initialMods = initialMods)
21512157
val lastClause =
21522158
params.nonEmpty && params.head.mods.flags.is(Implicit, butNot = Contextual)
2153-
params :: (if (lastClause) Nil else recur(firstClause = false))
2159+
params :: (if (lastClause) Nil else recur(firstClause = false, nparams + params.length))
2160+
}
2161+
else if (isContextual) {
2162+
val tps = commaSeparated(refinedType)
2163+
val params = tps.map(makeSyntheticParameter(nparams + 1, _, Contextual | Implicit))
2164+
params :: recur(firstClause = false, nparams + params.length)
21542165
}
21552166
else Nil
21562167
}
2157-
recur(firstClause = true)
2168+
recur(firstClause = true, 0)
21582169
}
21592170

21602171
/* -------- DEFS ------------------------------------------- */
@@ -2545,7 +2556,7 @@ object Parsers {
25452556
/** InstanceDef ::= [id] InstanceParams [‘of’ ConstrApps] [TemplateBody]
25462557
* | ‘val’ PatDef
25472558
* | ‘def’ MethodDef
2548-
* InstanceParams ::= [DefTypeParamClause] {‘with’ ‘(’ [DefParams] ‘)}
2559+
* InstanceParams ::= [DefTypeParamClause] {InstParamClause}
25492560
*/
25502561
def instanceDef(start: Offset, mods: Modifiers, instanceMod: Mod) = {
25512562
val mods1 = addMod(mods, instanceMod)

docs/docs/internals/syntax.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (Id[HkTypeParamClause] |
290290
291291
ClsParamClauses ::= {ClsParamClause}
292292
ClsParamClause ::= [nl] ‘(’ [[FunArgMods] ClsParams] ‘)’
293-
| ‘with’ (‘(’ ([[FunArgMods] ClsParams] ‘)’ | ParamTypes)
293+
| ‘with’ (‘(’ ([[FunArgMods] ClsParams] ‘)’ | ContextTypes)
294294
ClsParams ::= ClsParam {‘,’ ClsParam}
295295
ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var
296296
[{Modifier} (‘val’ | ‘var’) | ‘inline’] Param
@@ -299,10 +299,10 @@ Param ::= id ‘:’ ParamType [‘=’ Expr]
299299
300300
DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [FunArgMods] DefParams ‘)’]
301301
DefParamClause ::= [nl] ‘(’ [DefParams] ‘)’ | InstParamClause
302-
InstParamClause ::= ‘with’ (‘(’ [DefParams] ‘)’ | ParamTypes)
302+
InstParamClause ::= ‘with’ (‘(’ [DefParams] ‘)’ | ContextTypes)
303303
DefParams ::= DefParam {‘,’ DefParam}
304304
DefParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id.
305-
ParamTypes ::= InfixType {‘,’ InfixType}
305+
ContextTypes ::= RefinedType {‘,’ RefinedType}
306306
```
307307

308308
### Bindings and Imports

docs/docs/reference/instances/context-params.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,15 @@ f("abc")
6565
f("abc") with ctx
6666
(f with global)("abc") with ctx
6767
```
68+
Context parameters may be given either as a normal parameter list `(...)`
69+
or as a sequence of types. To distinguish the two, a leading `(` always indicates a parameter list.
6870

6971
## Syntax
7072

7173
Here is the new syntax of parameters and arguments seen as a delta from the [standard context free syntax of Scala 3](http://dotty.epfl.ch/docs/internals/syntax.html).
7274
```
7375
ClsParamClause ::= ...
74-
| ‘with’ (‘(’ [ClsParams] ‘)’ | ParamTypes)
76+
| ‘with’ (‘(’ [ClsParams] ‘)’ | ContextTypes)
7577
DefParamClause ::= ...
7678
| InstParamClause
7779
InfixExpr ::= ...

docs/docs/reference/instances/instance-defs.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ TmplDef ::= ...
170170
| ‘instance’ InstanceDef
171171
InstanceDef ::= [id] InstanceParams [‘of’ ConstrApps] [TemplateBody]
172172
InstanceParams ::= [DefTypeParamClause] {InstParamClause}
173-
InstParamClause ::= ‘with’ (‘(’ [DefParams] ‘)’ | ParamTypes)
174-
ParamTypes ::= InfixType {‘,’ InfixType}
173+
InstParamClause ::= ‘with’ (‘(’ [DefParams] ‘)’ | ContextTypes)
174+
ContextTypes ::= RefinedType {‘,’ RefinedType}
175175
```
176176
The identifier `id` can be omitted only if either the `of` part or the template body is present. If the `of` part is missing, the template body must define at least one extension method.

tests/pos/reference/instances.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ object Instances extends Common {
3737
if (x < y) -1 else if (x > y) +1 else 0
3838
}
3939

40-
instance ListOrd[T] with (ord: Ord[T]) of Ord[List[T]] {
40+
instance ListOrd[T] with Ord[T] of Ord[List[T]] {
4141
def (xs: List[T]) compareTo (ys: List[T]): Int = (xs, ys) match {
4242
case (Nil, Nil) => 0
4343
case (Nil, _) => -1
@@ -73,14 +73,14 @@ object Instances extends Common {
7373
ctx => x
7474
}
7575

76-
def maximum[T](xs: List[T]) with (cmp: Ord[T]): T =
76+
def maximum[T](xs: List[T]) with Ord[T]: T =
7777
xs.reduceLeft((x, y) => if (x < y) y else x)
7878

7979
def descending[T] with (asc: Ord[T]): Ord[T] = new Ord[T] {
8080
def (x: T) compareTo (y: T) = asc.compareTo(y)(x)
8181
}
8282

83-
def minimum[T](xs: List[T]) with (cmp: Ord[T]) =
83+
def minimum[T](xs: List[T]) with Ord[T] =
8484
maximum(xs) with descending
8585

8686
def test(): Unit = {
@@ -138,7 +138,7 @@ object Instances extends Common {
138138
println(summon[D[Int]])
139139
}
140140
locally {
141-
instance def g with (ctx: Context): D[Int] = new D[Int]
141+
instance def g with Context: D[Int] = new D[Int]
142142
println(summon[D[Int]])
143143
}
144144
}

0 commit comments

Comments
 (0)