Skip to content

Commit e5cbc24

Browse files
committed
Implement instance as a modifier
1 parent 8f6ce4b commit e5cbc24

File tree

5 files changed

+52
-54
lines changed

5 files changed

+52
-54
lines changed

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

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,8 +2292,9 @@ object Parsers {
22922292
}
22932293
}
22942294

2295-
/** DefDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr
2296-
* | this ParamClause ParamClauses `=' ConstrExpr
2295+
/** DefDef ::= MethodDef | ConstructorDef
2296+
* MethodDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr
2297+
* ConstructorDef ::= this ParamClause ParamClauses `=' ConstrExpr
22972298
* DefDcl ::= DefSig `:' Type
22982299
* DefSig ::= ‘(’ DefParam ‘)’ [nl] id [DefTypeParamClause] ParamClauses
22992300
*/
@@ -2307,7 +2308,8 @@ object Parsers {
23072308
true
23082309
}
23092310
}
2310-
if (in.token == THIS) {
2311+
val isInstance = mods.hasMod(Predef.classOf[Mod.Instance])
2312+
if (!isInstance && in.token == THIS) {
23112313
in.nextToken()
23122314
val vparamss = paramClauses()
23132315
if (vparamss.isEmpty || vparamss.head.take(1).exists(_.mods.is(Implicit)))
@@ -2331,7 +2333,7 @@ object Parsers {
23312333
val mods1 = addFlag(mods, flags)
23322334
val name = ident()
23332335
val tparams = typeParamClauseOpt(ParamOwner.Def)
2334-
val vparamss = paramClauses() match {
2336+
val vparamss = paramClauses(ofInstance = isInstance) match {
23352337
case rparams :: rparamss if leadingParamss.nonEmpty && !isLeftAssoc(name) =>
23362338
rparams :: leadingParamss ::: rparamss
23372339
case rparamss =>
@@ -2540,46 +2542,38 @@ object Parsers {
25402542
Template(constr, parents, Nil, EmptyValDef, Nil)
25412543
}
25422544

2543-
/** InstanceDef ::= [id] InstanceParams [‘for’ ConstrApps] [TemplateBody]
2544-
* | id InstanceParams ‘:’ Type ‘=’ Expr
2545-
* | id ‘:’ ‘=>’ Type ‘=’ Expr
2546-
* | id ‘=’ Expr
2545+
/** InstanceDef ::= [id] InstanceParams [‘of’ ConstrApps] [TemplateBody]
2546+
* | ‘val’ PatDef
2547+
* | ‘def’ MethodDef
25472548
* InstanceParams ::= [DefTypeParamClause] {‘with’ ‘(’ [DefParams] ‘)}
25482549
*/
2549-
def instanceDef(start: Offset, mods: Modifiers, instanceMod: Mod) = atSpan(start, nameStart) {
2550-
val name = if (isIdent && !isIdent(nme.of)) ident() else EmptyTermName
2551-
val tparams = typeParamClauseOpt(ParamOwner.Def)
2552-
val vparamss = paramClauses(ofInstance = true)
2553-
val parents =
2554-
if (isIdent(nme.of)) {
2555-
in.nextToken()
2556-
tokenSeparated(WITH, constrApp)
2557-
}
2558-
else Nil
2559-
newLineOptWhenFollowedBy(LBRACE)
2560-
if (name.isEmpty && in.token != LBRACE)
2561-
syntaxErrorOrIncomplete(ExpectedTokenButFound(LBRACE, in.token))
2562-
var mods1 = addMod(mods, instanceMod)
2563-
val wdef =
2564-
if (in.token == LBRACE) {
2565-
val templ = templateBodyOpt(makeConstructor(tparams, vparamss), parents, Nil, isEnum = false)
2550+
def instanceDef(start: Offset, mods: Modifiers, instanceMod: Mod) = {
2551+
val mods1 = addMod(mods, instanceMod)
2552+
if (in.token == VAL) {
2553+
in.nextToken()
2554+
patDefOrDcl(start, mods1)
2555+
}
2556+
else if (in.token == DEF) {
2557+
in.nextToken()
2558+
defDefOrDcl(start, mods1)
2559+
}
2560+
else atSpan(start, nameStart) {
2561+
val name = if (isIdent && !isIdent(nme.of)) ident() else EmptyTermName
2562+
val tparams = typeParamClauseOpt(ParamOwner.Def)
2563+
val vparamss = paramClauses(ofInstance = true)
2564+
val parents =
2565+
if (isIdent(nme.of)) {
2566+
in.nextToken()
2567+
tokenSeparated(WITH, constrApp)
2568+
}
2569+
else Nil
2570+
newLineOptWhenFollowedBy(LBRACE)
2571+
val templ = templateBodyOpt(makeConstructor(tparams, vparamss), parents, Nil, isEnum = false)
2572+
val instDef =
25662573
if (tparams.isEmpty && vparamss.isEmpty) ModuleDef(name, templ)
25672574
else TypeDef(name.toTypeName, templ)
2568-
}
2569-
else {
2570-
val tpt = typedOpt()
2571-
if (tpt.isEmpty && in.token != EQUALS)
2572-
syntaxErrorOrIncomplete(ExpectedTokenButFound(LBRACE, in.token))
2573-
val rhs =
2574-
if (in.token == EQUALS) {
2575-
in.nextToken()
2576-
expr()
2577-
}
2578-
else EmptyTree
2579-
if (tparams.isEmpty && vparamss.isEmpty) ValDef(name, tpt, rhs)
2580-
else DefDef(name, tparams, vparamss, tpt, rhs)
2581-
}
2582-
finalizeDef(wdef, mods1, start)
2575+
finalizeDef(instDef, mods1, start)
2576+
}
25832577
}
25842578

25852579
/* -------- TEMPLATES ------------------------------------------- */

docs/docs/internals/syntax.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,14 +352,16 @@ Def ::= ‘val’ PatDef
352352
| ‘var’ VarDef
353353
| ‘def’ DefDef
354354
| ‘type’ {nl} TypeDcl
355+
| ‘instance’ {nl} InstanceDef
355356
| TmplDef
356357
| INT
357358
PatDef ::= Pattern2 {‘,’ Pattern2} [‘:’ Type] ‘=’ Expr PatDef(_, pats, tpe?, expr)
358359
VarDef ::= PatDef
359360
| ids ‘:’ Type ‘=’ ‘_’
360-
DefDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr)
361+
DefDef ::= MethodDef | ConstructorDef
362+
MethodDef ::= DefSig [(‘:’ | ‘<:’) Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr)
361363
| DefSig [nl] ‘{’ Block ‘}’ DefDef(_, name, tparams, vparamss, tpe, Block)
362-
| ‘this’ DefParamClause DefParamClauses DefDef(_, <init>, Nil, vparamss, EmptyTree, expr | Block)
364+
ConstructorDef ::= ‘this’ DefParamClause DefParamClauses DefDef(_, <init>, Nil, vparamss, EmptyTree, expr | Block)
363365
(‘=’ ConstrExpr | [nl] ConstrBlock)
364366
365367
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
@@ -372,6 +374,8 @@ ConstrMods ::= {Annotation} [AccessModifier]
372374
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
373375
EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template)
374376
InstanceDef ::= [id] InstanceParams [‘of’ ConstrApps] [TemplateBody]
377+
| ‘val’ PatDef
378+
| ‘def’ MethodDef
375379
InstanceParams ::= [DefTypeParamClause] {InstParamClause}
376380
Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats)
377381
InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ instance ListOrd[T: Ord] for Ord[List[T]] {
2828
}
2929
}
3030
```
31-
3231
Instance definitions can be seen as shorthands for what is currently expressed with implicit object and method definitions.
3332
For instance, the definition of instance `IntOrd` above defines an implicit value of type `Ord[Int]`. It is hence equivalent
3433
to the following implicit object definition:

docs/docs/reference/instances/replacing-implicits.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ instance val ctx = localCtx
2222
instance def f[T]: C[T] = new C[T]
2323
instance def g with (ctx: Context): D = new D(ctx)
2424
```
25-
25+
The `instance` modifier must be followed directly by `val` or `def`; no other intervening modifiers are permitted.
2626
When used as a modifier, `instance` generally has the same meaning as the current `implicit` modifier, with the following exceptions:
2727

2828
1. `instance def` definitions can only have context parameters in `with` clauses. Old style `implicit` parameters are not supported.
@@ -59,8 +59,9 @@ def summon[T] with (x: T) = x
5959

6060
The syntax changes for this page are summarized as follows:
6161
```
62-
LocalModifier ::= ...
63-
| ‘instance’
62+
InstanceDef ::= ...
63+
| ‘val’ PatDef
64+
| ‘def’ MethodDef
6465
```
6566
In addition, the `implicit` modifier is removed together with all [productions]((http://dotty.epfl.ch/docs/internals/syntax.html) that reference it.
6667

tests/pos/reference/instances.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ object Instances extends Common {
104104
trait SymDeco {
105105
def (sym: Symbol) name: String
106106
}
107-
instance symDeco: SymDeco
107+
instance def symDeco: SymDeco
108108
}
109109
object TastyImpl extends TastyAPI {
110110
type Symbol = String
111-
instance symDeco: SymDeco = new SymDeco {
111+
instance val symDeco: SymDeco = new SymDeco {
112112
def (sym: Symbol) name = sym
113113
}
114114
}
@@ -118,27 +118,27 @@ object Instances extends Common {
118118
class C with (ctx: Context) {
119119
def f() = {
120120
locally {
121-
instance ctx = this.ctx
121+
instance val ctx = this.ctx
122122
println(summon[Context].value)
123123
}
124124
locally {
125-
lazy instance ctx = this.ctx
125+
lazy instance val ctx = this.ctx
126126
println(summon[Context].value)
127127
}
128128
locally {
129-
instance ctx: Context = this.ctx
129+
instance val ctx: Context = this.ctx
130130
println(summon[Context].value)
131131
}
132132
locally {
133-
instance ctx with (): Context = this.ctx
133+
instance def ctx: Context = this.ctx
134134
println(summon[Context].value)
135135
}
136136
locally {
137-
instance f[T]: D[T] = new D[T]
137+
instance def f[T]: D[T] = new D[T]
138138
println(summon[D[Int]])
139139
}
140140
locally {
141-
instance g with (ctx: Context): D[Int] = new D[Int]
141+
instance def g with (ctx: Context): D[Int] = new D[Int]
142142
println(summon[D[Int]])
143143
}
144144
}

0 commit comments

Comments
 (0)