Skip to content

Commit f64241c

Browse files
committed
Syntax for computed type definitions
1 parent 43f276c commit f64241c

File tree

9 files changed

+65
-25
lines changed

9 files changed

+65
-25
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ object desugar {
201201
case (vparam :: vparams) :: vparamss1 =>
202202
def defaultGetter: DefDef =
203203
DefDef(
204-
name = DefaultGetterName(meth.name, n),
204+
name = DefaultGetterName(meth.name.asTermName, n),
205205
tparams = meth.tparams.map(tparam => dropContextBound(toDefParam(tparam))),
206206
vparamss = takeUpTo(normalizedVparamss.nestedMap(toDefParam), n),
207207
tpt = TypeTree(),

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,12 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
339339
case _ => false
340340
}
341341

342+
/** Is this the RHS of a transparnt type def, which needs to be represented as a DefDef? */
343+
def isTypeDefRHS(tree: Tree): Boolean = tree match {
344+
case tree: If => true
345+
case _ => false
346+
}
347+
342348
// todo: fill with other methods from TreeInfo that only apply to untpd.Tree's
343349
}
344350

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -492,8 +492,10 @@ object Trees {
492492

493493
/** if cond then thenp else elsep */
494494
case class If[-T >: Untyped] private[ast] (cond: Tree[T], thenp: Tree[T], elsep: Tree[T])
495-
extends TermTree[T] {
495+
extends Tree[T] {
496496
type ThisTree[-T >: Untyped] = If[T]
497+
override def isTerm = thenp.isTerm
498+
override def isType = thenp.isType
497499
}
498500

499501
/** A closure with an environment and a reference to a method.
@@ -697,8 +699,11 @@ object Trees {
697699
protected def force(x: AnyRef) = preRhs = x
698700
}
699701

700-
/** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */
701-
case class DefDef[-T >: Untyped] private[ast] (name: TermName, tparams: List[TypeDef[T]],
702+
/** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs
703+
* or
704+
* mods type[tparams](vparams_1)...(vparams_n): tpt = rhs
705+
*/
706+
case class DefDef[-T >: Untyped] private[ast] (name: Name, tparams: List[TypeDef[T]],
702707
vparamss: List[List[ValDef[T]]], tpt: Tree[T], private var preRhs: LazyTree)
703708
extends ValOrDefDef[T] {
704709
type ThisTree[-T >: Untyped] = DefDef[T]
@@ -1085,7 +1090,7 @@ object Trees {
10851090
case tree: ValDef if (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree
10861091
case _ => finalize(tree, untpd.ValDef(name, tpt, rhs))
10871092
}
1088-
def DefDef(tree: Tree)(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree): DefDef = tree match {
1093+
def DefDef(tree: Tree)(name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree): DefDef = tree match {
10891094
case tree: DefDef if (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree
10901095
case _ => finalize(tree, untpd.DefDef(name, tparams, vparamss, tpt, rhs))
10911096
}
@@ -1132,7 +1137,7 @@ object Trees {
11321137
UnApply(tree: Tree)(fun, implicits, patterns)
11331138
def ValDef(tree: ValDef)(name: TermName = tree.name, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs): ValDef =
11341139
ValDef(tree: Tree)(name, tpt, rhs)
1135-
def DefDef(tree: DefDef)(name: TermName = tree.name, tparams: List[TypeDef] = tree.tparams, vparamss: List[List[ValDef]] = tree.vparamss, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs): DefDef =
1140+
def DefDef(tree: DefDef)(name: Name = tree.name, tparams: List[TypeDef] = tree.tparams, vparamss: List[List[ValDef]] = tree.vparamss, tpt: Tree = tree.tpt, rhs: LazyTree = tree.unforcedRhs): DefDef =
11361141
DefDef(tree: Tree)(name, tparams, vparamss, tpt, rhs)
11371142
def TypeDef(tree: TypeDef)(name: TypeName = tree.name, rhs: Tree = tree.rhs): TypeDef =
11381143
TypeDef(tree: Tree)(name, rhs)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
294294
def Alternative(trees: List[Tree]): Alternative = new Alternative(trees)
295295
def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree]): UnApply = new UnApply(fun, implicits, patterns)
296296
def ValDef(name: TermName, tpt: Tree, rhs: LazyTree): ValDef = new ValDef(name, tpt, rhs)
297-
def DefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree): DefDef = new DefDef(name, tparams, vparamss, tpt, rhs)
297+
def DefDef(name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree): DefDef = new DefDef(name, tparams, vparamss, tpt, rhs)
298298
def TypeDef(name: TypeName, rhs: Tree): TypeDef = new TypeDef(name, rhs)
299299
def Template(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList): Template = new Template(constr, parents, self, body)
300300
def Import(expr: Tree, selectors: List[untpd.Tree]): Import = new Import(expr, selectors)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ object Comments {
121121

122122
tree match {
123123
case tree: untpd.DefDef =>
124-
val newName = ctx.freshNames.newName(tree.name, NameKinds.DocArtifactName)
124+
val newName = ctx.freshNames.newName(tree.name.toTermName, NameKinds.DocArtifactName)
125125
untpd.DefDef(newName, tree.tparams, tree.vparamss, tree.tpt, tree.rhs)
126126
case _ =>
127127
ctx.error(ProperDefinitionNotFound(), codePos)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ object JavaParsers {
784784
// If the annotation has a default value we don't need to parse it, providing
785785
// any value at all is enough to typecheck usages of annotations correctly.
786786
val defaultParam = if (hasDefault) unimplementedExpr else EmptyTree
787-
makeParam(dd.name, dd.tpt, defaultParam)
787+
makeParam(dd.name.asTermName, dd.tpt, defaultParam)
788788
}
789789
val constr = DefDef(nme.CONSTRUCTOR,
790790
List(), List(constructorParams), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined))

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

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ object Parsers {
4646
}
4747

4848
@sharable object ParamOwner extends Enumeration {
49-
val Class, Type, TypeParam, Def = Value
49+
val Class, Type, TypeParam, Def, Constructor = Value
5050
}
5151

5252
private implicit class AddDeco(val buf: ListBuffer[Tree]) extends AnyVal {
@@ -714,6 +714,7 @@ object Parsers {
714714
}
715715

716716
/* ------------- TYPES ------------------------------------------------------ */
717+
717718
/** Same as [[typ]], but if this results in a wildcard it emits a syntax error and
718719
* returns a tree for type `Any` instead.
719720
*/
@@ -1055,6 +1056,21 @@ object Parsers {
10551056
case None => t
10561057
}
10571058

1059+
/** TypeRHS ::= ‘if’ Expr ‘then’ TypeRHS ‘else’ TypeRHS
1060+
* | Type
1061+
*/
1062+
def typeRHS(): Tree =
1063+
if (in.token == IF)
1064+
atPos(in.skipToken()) {
1065+
val cond = typeRHS()
1066+
accept(THEN)
1067+
val thenp = typeRHS()
1068+
accept(ELSE)
1069+
val elsep = expr()
1070+
If(cond, thenp, elsep)
1071+
}
1072+
else toplevelTyp()
1073+
10581074
/* ----------- EXPRESSIONS ------------------------------------------------ */
10591075

10601076
/** EqualsExpr ::= `=' Expr
@@ -1831,14 +1847,15 @@ object Parsers {
18311847
*/
18321848
def typeParamClause(ownerKind: ParamOwner.Value): List[TypeDef] = inBrackets {
18331849
def typeParam(): TypeDef = {
1834-
val isConcreteOwner = ownerKind == ParamOwner.Class || ownerKind == ParamOwner.Def
1850+
val isDefOwner = ownerKind == ParamOwner.Def || ownerKind == ParamOwner.Constructor
1851+
val isConcreteOwner = isDefOwner || ownerKind == ParamOwner.Class
18351852
val start = in.offset
18361853
val mods = atPos(start) {
18371854
annotsAsMods() | {
18381855
if (ownerKind == ParamOwner.Class) Param | PrivateLocal
18391856
else Param
18401857
} | {
1841-
if (ownerKind != ParamOwner.Def)
1858+
if (!isDefOwner)
18421859
if (isIdent(nme.raw.PLUS)) { in.nextToken(); Covariant }
18431860
else if (isIdent(nme.raw.MINUS)) { in.nextToken(); Contravariant }
18441861
else EmptyFlags
@@ -1875,14 +1892,14 @@ object Parsers {
18751892
* DefParam ::= {Annotation} [`inline'] Param
18761893
* Param ::= id `:' ParamType [`=' Expr]
18771894
*/
1878-
def paramClauses(owner: Name, ofCaseClass: Boolean = false): List[List[ValDef]] = {
1895+
def paramClauses(ownerKind: ParamOwner.Value, ofCaseClass: Boolean = false): List[List[ValDef]] = {
18791896
var imods: Modifiers = EmptyModifiers
18801897
var implicitOffset = -1 // use once
18811898
var firstClauseOfCaseClass = ofCaseClass
18821899
def param(): ValDef = {
18831900
val start = in.offset
18841901
var mods = annotsAsMods()
1885-
if (owner.isTypeName) {
1902+
if (ownerKind == ParamOwner.Class) {
18861903
mods = addFlag(modifiers(start = mods), ParamAccessor)
18871904
mods =
18881905
atPos(start, in.offset) {
@@ -1909,7 +1926,7 @@ object Parsers {
19091926
atPos(start, nameStart) {
19101927
val name = ident()
19111928
accept(COLON)
1912-
if (in.token == ARROW && owner.isTypeName && !(mods is Local))
1929+
if (in.token == ARROW && ownerKind == ParamOwner.Class && !(mods is Local))
19131930
syntaxError(VarValParametersMayNotBeCallByName(name, mods is Mutable))
19141931
val tpt = paramType()
19151932
val default =
@@ -1936,7 +1953,7 @@ object Parsers {
19361953
funArgMods()
19371954
}
19381955
}
1939-
funArgMods()
1956+
if (ownerKind != ParamOwner.Type) funArgMods()
19401957

19411958
commaSeparated(() => param())
19421959
}
@@ -1953,7 +1970,7 @@ object Parsers {
19531970
}
19541971
val start = in.offset
19551972
val result = clauses()
1956-
if (owner == nme.CONSTRUCTOR && (result.isEmpty || (result.head take 1 exists (_.mods is Implicit)))) {
1973+
if (ownerKind == ParamOwner.Constructor && (result.isEmpty || (result.head take 1 exists (_.mods is Implicit)))) {
19571974
in.token match {
19581975
case LBRACKET => syntaxError("no type parameters allowed here")
19591976
case EOF => incompleteInputError(AuxConstructorNeedsNonImplicitParameter())
@@ -2121,7 +2138,7 @@ object Parsers {
21212138
}
21222139
if (in.token == THIS) {
21232140
in.nextToken()
2124-
val vparamss = paramClauses(nme.CONSTRUCTOR)
2141+
val vparamss = paramClauses(ParamOwner.Constructor)
21252142
if (in.isScala2Mode) newLineOptWhenFollowedBy(LBRACE)
21262143
val rhs = {
21272144
if (!(in.token == LBRACE && scala2ProcedureSyntax(""))) accept(EQUALS)
@@ -2132,7 +2149,7 @@ object Parsers {
21322149
val mods1 = addFlag(mods, Method)
21332150
val name = ident()
21342151
val tparams = typeParamClauseOpt(ParamOwner.Def)
2135-
val vparamss = paramClauses(name)
2152+
val vparamss = paramClauses(ParamOwner.Def)
21362153
var tpt = fromWithinReturnType(typedOpt())
21372154
if (in.isScala2Mode) newLineOptWhenFollowedBy(LBRACE)
21382155
val rhs =
@@ -2183,19 +2200,27 @@ object Parsers {
21832200
Block(stats, Literal(Constant(())))
21842201
}
21852202

2186-
/** TypeDef ::= type id [TypeParamClause] `=' Type
2187-
* TypeDcl ::= type id [TypeParamClause] TypeBounds
2203+
/** TypeDcl ::= id [TypTypeParamClause] {DefParamClause} [‘:’ Type] ‘=’ TypeRHS
2204+
* | id [HkTypeParamClause] TypeBounds
21882205
*/
21892206
def typeDefOrDcl(start: Offset, mods: Modifiers): Tree = {
21902207
newLinesOpt()
21912208
atPos(start, nameStart) {
21922209
val name = ident().toTypeName
21932210
val tparams = typeParamClauseOpt(ParamOwner.Type)
2211+
val vparamss = paramClauses(ParamOwner.Type)
2212+
val tpt = typedOpt()
2213+
val isDef = !vparamss.isEmpty || !tpt.isEmpty
21942214
in.token match {
21952215
case EQUALS =>
21962216
in.nextToken()
2197-
TypeDef(name, lambdaAbstract(tparams, toplevelTyp())).withMods(mods).setComment(in.getDocComment(start))
2217+
val rhs = typeRHS()
2218+
val res =
2219+
if (isTypeDefRHS(rhs) || isDef) DefDef(name, tparams, vparamss, tpt, rhs)
2220+
else TypeDef(name, lambdaAbstract(tparams, rhs))
2221+
res.withMods(mods).setComment(in.getDocComment(start))
21982222
case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | EOF =>
2223+
if (isDef) syntaxError("`=' expected")
21992224
TypeDef(name, lambdaAbstract(tparams, typeBounds())).withMods(mods).setComment(in.getDocComment(start))
22002225
case _ =>
22012226
syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals(in.token))
@@ -2245,7 +2270,7 @@ object Parsers {
22452270
def classConstr(owner: Name, isCaseClass: Boolean = false): DefDef = atPos(in.lastOffset) {
22462271
val tparams = typeParamClauseOpt(ParamOwner.Class)
22472272
val cmods = fromWithinClassConstr(constrModsOpt(owner))
2248-
val vparamss = paramClauses(owner, isCaseClass)
2273+
val vparamss = paramClauses(ParamOwner.Class, isCaseClass)
22492274
makeConstructor(tparams, vparamss).withMods(cmods)
22502275
}
22512276

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ object messages {
12601260
|""".stripMargin
12611261
}
12621262

1263-
case class OverloadedOrRecursiveMethodNeedsResultType(tree: Names.TermName)(implicit ctx: Context)
1263+
case class OverloadedOrRecursiveMethodNeedsResultType(tree: Names.Name)(implicit ctx: Context)
12641264
extends Message(OverloadedOrRecursiveMethodNeedsResultTypeID) {
12651265
val kind = "Syntax"
12661266
val msg = hl"""overloaded or recursive method ${tree} needs return type"""

docs/docs/internals/syntax.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ NamedTypeArgs ::= ‘[’ NamedTypeArg {‘,’ NamedTypeArg} ‘]’
151151
Refinement ::= ‘{’ [RefineDcl] {semi [RefineDcl]} ‘}’ ds
152152
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] | INT TypeBoundsTree(lo, hi)
153153
TypeParamBounds ::= TypeBounds {‘<%’ Type} {‘:’ Type} ContextBounds(typeBounds, tps)
154+
155+
TypeRHS ::= ‘if’ Expr ‘then’ TypeRHS ‘else’ TypeRHS If(cond, thenp, elsep)
156+
| Type
154157
```
155158

156159
### Expressions
@@ -310,7 +313,8 @@ ValDcl ::= ids ‘:’ Type
310313
VarDcl ::= ids ‘:’ Type PatDef(_, ids, tpe, EmptyTree)
311314
DefDcl ::= DefSig [‘:’ Type] DefDef(_, name, tparams, vparamss, tpe, EmptyTree)
312315
DefSig ::= id [DefTypeParamClause] DefParamClauses
313-
TypeDcl ::= id [TypTypeParamClause] [‘=’ Type] TypeDefTree(_, name, tparams, tpt)
316+
TypeDcl ::= id [TypTypeParamClause] {DefParamClause} [‘:’ Type] TypeDefTree(_, name, tparams, tpt)
317+
‘=’ TypeRHS
314318
| id [HkTypeParamClause] TypeBounds TypeDefTree(_, name, tparams, bounds)
315319
316320
Def ::= ‘val’ PatDef

0 commit comments

Comments
 (0)