Skip to content

Commit

Permalink
Spec: Refactoring: Merge "definitions" and "declarations".
Browse files Browse the repository at this point in the history
Previously, abstract members were syntactically separate from
concrete members, and referred to "declarations", as opposed to
"definitions".

In this commit, all of them become "definitions". There are
abstract definitions and concrete definitions. They share their
syntactic productions.

This will allow to more easily introduce more kinds of definitions
that can be abstract or concrete in deeper productions of the
grammar, such as extension methods.

[Cherry-picked 86d06b4][modified]
  • Loading branch information
Kordyjan committed Dec 7, 2023
1 parent cbd4b39 commit b242623
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 162 deletions.
28 changes: 10 additions & 18 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3541,12 +3541,8 @@ object Parsers {
/** Def ::= val PatDef
* | var VarDef
* | def DefDef
* | type {nl} TypeDcl
* | type {nl} TypeDef
* | TmplDef
* Dcl ::= val ValDcl
* | var ValDcl
* | def DefDcl
* | type {nl} TypeDcl
* EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
*/
def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match {
Expand All @@ -3567,12 +3563,10 @@ object Parsers {
tmplDef(start, mods)
}

/** PatDef ::= ids [‘:’ Type] ‘=’ Expr
* | Pattern2 [‘:’ Type] ‘=’ Expr
/** PatDef ::= ids [‘:’ Type] [‘=’ Expr]
* | Pattern2 [‘:’ Type] [‘=’ Expr]
* VarDef ::= PatDef
* | id {`,' id} `:' Type `=' `_' (deprecated in 3.x)
* ValDcl ::= id {`,' id} `:' Type
* VarDcl ::= id {`,' id} `:' Type
* | id {`,' id} `:' Type `=' `_' (deprecated in 3.x)
*/
def patDefOrDcl(start: Offset, mods: Modifiers): Tree = atSpan(start, nameStart) {
val first = pattern2()
Expand Down Expand Up @@ -3621,9 +3615,8 @@ object Parsers {
}
}

/** DefDef ::= DefSig [‘:’ Type] ‘=’ Expr
/** DefDef ::= DefSig [‘:’ Type] [‘=’ Expr]
* | this TypelessClauses [DefImplicitClause] `=' ConstrExpr
* DefDcl ::= DefSig `:' Type
* DefSig ::= id [DefTypeParamClause] DefTermParamClauses
*
* if clauseInterleaving is enabled:
Expand Down Expand Up @@ -3721,7 +3714,7 @@ object Parsers {
argumentExprss(mkApply(Ident(nme.CONSTRUCTOR), argumentExprs()))
}

/** TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type]
/** TypeDef ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type]
*/
def typeDefOrDcl(start: Offset, mods: Modifiers): Tree = {
newLinesOpt()
Expand Down Expand Up @@ -4208,7 +4201,6 @@ object Parsers {
* TemplateStat ::= Import
* | Export
* | Annotations Modifiers Def
* | Annotations Modifiers Dcl
* | Extension
* | Expr1
* |
Expand Down Expand Up @@ -4238,10 +4230,10 @@ object Parsers {
}

/** RefineStatSeq ::= RefineStat {semi RefineStat}
* RefineStat ::= ‘val’ VarDcl
* | ‘def’ DefDcl
* | ‘type’ {nl} TypeDcl
* (in reality we admit Defs and vars and filter them out afterwards in `checkLegal`)
* RefineStat ::= ‘val’ VarDef
* | ‘def’ DefDef
* | ‘type’ {nl} TypeDef
* (in reality we admit class defs and vars and filter them out afterwards in `checkLegal`)
*/
def refineStatSeq(): List[Tree] = {
val stats = new ListBuffer[Tree]
Expand Down
29 changes: 12 additions & 17 deletions docs/_docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ ParamType ::= [‘=>’] ParamValueType
ParamValueType ::= [‘into’] ExactParamType Into(t)
ExactParamType ::= ParamValueType [‘*’] PostfixOp(t, "*")
TypeArgs ::= ‘[’ Types ‘]’ ts
Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>> ds
Refinement ::= :<<< [RefineDef] {semi [RefineDef]} >>> ds
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi)
TypeParamBounds ::= TypeBounds {‘:’ Type} ContextBounds(typeBounds, tps)
Types ::= Type {‘,’ Type}
Expand Down Expand Up @@ -412,29 +412,24 @@ EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ |
| ‘new’ | ‘this’ | ‘given’ | ‘extension’ | ‘val’
```

### Declarations and Definitions
### Definitions
```ebnf
RefineDcl ::= ‘val’ ValDcl
| ‘def’ DefDcl
| ‘type’ {nl} TypeDcl
Dcl ::= RefineDcl
| ‘var’ VarDcl
ValDcl ::= ids ‘:’ Type PatDef(_, ids, tpe, EmptyTree)
VarDcl ::= ids ‘:’ Type PatDef(_, ids, tpe, EmptyTree)
DefDcl ::= DefSig ‘:’ Type DefDef(_, name, paramss, tpe, EmptyTree)
DefSig ::= id [DefParamClauses] [DefImplicitClause]
TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds TypeDefTree(_, name, tparams, bound
[‘=’ Type]
RefineDef ::= ‘val’ ValDef
| ‘def’ DefDef
| ‘type’ {nl} TypeDef
Def ::= ‘val’ PatDef
| ‘var’ PatDef
| ‘def’ DefDef
| ‘type’ {nl} TypeDcl
| ‘type’ {nl} TypeDef
| TmplDef
PatDef ::= ids [‘:’ Type] ‘=’ Expr
| Pattern2 [‘:’ Type] ‘=’ Expr PatDef(_, pats, tpe?, expr)
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr DefDef(_, name, paramss, tpe, expr)
PatDef ::= ids [‘:’ Type] [‘=’ Expr]
| Pattern2 [‘:’ Type] [‘=’ Expr] PatDef(_, pats, tpe?, expr)
DefDef ::= DefSig [‘:’ Type] [‘=’ Expr] DefDef(_, name, paramss, tpe, expr)
| ‘this’ TypelessClauses [DefImplicitClause] ‘=’ ConstrExpr DefDef(_, <init>, vparamss, EmptyTree, expr | Block)
DefSig ::= id [DefParamClauses] [DefImplicitClause]
TypeDef ::= id [TypeParamClause] {FunParamClause} TypeBounds TypeDefTree(_, name, tparams, bound
[‘=’ Type]
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
| [‘case’] ‘object’ ObjectDef
Expand Down
4 changes: 2 additions & 2 deletions docs/_spec/01-lexical-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,13 @@ Multiple newline tokens are accepted in the following places (note that a semico

- between the condition of a [conditional expression](06-expressions.html#conditional-expressions) or [while loop](06-expressions.html#while-loop-expressions) and the next following expression,
- between the enumerators of a [for-comprehension](06-expressions.html#for-comprehensions-and-for-loops) and the next following expression, and
- after the initial `type` keyword in a [type definition or declaration](04-basic-declarations-and-definitions.html#type-declarations-and-type-aliases).
- after the initial `type` keyword in a [type definition](04-basic-definitions.html#type-member-definitions).

A single new line token is accepted

- in front of an opening brace ‘{’, if that brace is a legal continuation of the current statement or expression,
- after an [infix operator](06-expressions.html#prefix,-infix,-and-postfix-operations), if the first token on the next line can start an expression,
- in front of a [parameter clause](04-basic-declarations-and-definitions.html#function-declarations-and-definitions), and
- in front of a [parameter clause](04-basic-definitions.html#method-definitions), and
- after an [annotation](11-annotations.html#user-defined-annotations).

> The newline tokens between the two lines are not treated as statement separators.
Expand Down
8 changes: 4 additions & 4 deletions docs/_spec/02-identifiers-names-and-scopes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ chapter: 2

Names in Scala identify types, values, methods, and classes which are collectively called _entities_.
Names are introduced by local
[definitions and declarations](04-basic-declarations-and-definitions.html#basic-declarations-and-definitions),
[definitions](04-basic-definitions.html#basic-definitions),
[inheritance](05-classes-and-objects.html#class-members),
[import clauses](04-basic-declarations-and-definitions.html#import-clauses), or
[import clauses](04-basic-definitions.html#import-clauses), or
[package clauses](09-top-level-definitions.html#packagings)
which are collectively called _bindings_.

Bindings of different kinds have precedence defined on them:

1. Definitions and declarations that are local, inherited, or made available by a package clause and also defined in the same compilation unit as the reference to them, have the highest precedence.
1. Definitions that are local, inherited, or made available by a package clause and also defined in the same compilation unit as the reference to them, have the highest precedence.
1. Explicit imports have the next highest precedence.
1. Wildcard imports have the next highest precedence.
1. Definitions made available by a package clause, but not also defined in the same compilation unit as the reference to them, as well as imports which are supplied by the compiler but not explicitly written in source code, have the lowest precedence.
Expand Down Expand Up @@ -48,7 +48,7 @@ A reference to an unqualified (type- or term-) identifier ´x´ is bound by the

It is an error if no such binding exists.
If ´x´ is bound by an import clause, then the simple name ´x´ is taken to be equivalent to the qualified name to which ´x´ is mapped by the import clause.
If ´x´ is bound by a definition or declaration, then ´x´ refers to the entity introduced by that binding.
If ´x´ is bound by a definition, then ´x´ refers to the entity introduced by that binding.
In that case, the type of ´x´ is the type of the referenced entity.

A reference to a qualified (type- or term-) identifier ´e.x´ refers to the member of the type ´T´ of ´e´ which has the name ´x´ in the same namespace as the identifier.
Expand Down
41 changes: 21 additions & 20 deletions docs/_spec/03-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ SimpleRef ::= id
ParamType ::= [‘=>’] ParamValueType
ParamValueType ::= ParamValueType [‘*’]
TypeArgs ::= ‘[’ TypesOrWildcards ‘]’
Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>>
Refinement ::= :<<< [RefineDef] {semi [RefineDef]} >>>
FunTypeArgs ::= InfixType
| ‘(’ [ FunArgTypes ] ‘)’
Expand All @@ -51,9 +51,9 @@ TypeLambdaParam ::= {Annotation} (id | ‘_’) [TypeParamClause] TypeBou
TypeParamClause ::= ‘[’ VariantTypeParam {‘,’ VariantTypeParam} ‘]’
VariantTypeParam ::= {Annotation} [‘+’ | ‘-’] (id | ‘_’) [TypeParamClause] TypeBounds
RefineDcl ::= ‘val’ ValDcl
| ‘def’ DefDcl
| ‘type’ {nl} TypeDcl
RefineDef ::= ‘val’ ValDef
| ‘def’ DefDef
| ‘type’ {nl} TypeDef
TypeBounds ::= [‘>:’ Type] [‘<:’ Type]
Expand Down Expand Up @@ -193,11 +193,11 @@ TypedFunParam ::= id ‘:’ Type

The concrete function type ´(T_1, ..., T_n) \Rightarrow R´ represents the set of function values that take arguments of types ´T_1, ..., Tn´ and yield results of type ´R´.
The case of exactly one argument type ´T \Rightarrow R´ is a shorthand for ´(T) \Rightarrow R´.
An argument type of the form ´\Rightarrow T´ represents a [call-by-name parameter](04-basic-declarations-and-definitions.html#by-name-parameters) of type ´T´.
An argument type of the form ´\Rightarrow T´ represents a [call-by-name parameter](04-basic-definitions.html#by-name-parameters) of type ´T´.

Function types associate to the right, e.g. ´S \Rightarrow T \Rightarrow R´ is the same as ´S \Rightarrow (T \Rightarrow R)´.

Function types are [covariant](04-basic-declarations-and-definitions.md#variance-annotations) in their result type and [contravariant](04-basic-declarations-and-definitions.md#variance-annotations) in their argument types.
Function types are [covariant](04-basic-definitions.md#variance-annotations) in their result type and [contravariant](04-basic-definitions.md#variance-annotations) in their argument types.

Function types translate into internal class types that define an `apply` method.
Specifically, the ´n´-ary function type ´(T_1, ..., T_n) \Rightarrow R´ translates to the internal class type `scala.Function´_n´[´T_1´, ..., ´T_n´, ´R´]`.
Expand Down Expand Up @@ -253,23 +253,24 @@ Notes:
RefinedType ::= AnnotType {[nl] Refinement}
SimpleType1 ::= ...
| Refinement
Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>>
Refinement ::= :<<< [RefineDef] {semi [RefineDef]} >>>
RefineDcl ::= ‘val’ ValDcl
| ‘def’ DefDcl
| ‘type’ {nl} TypeDcl
RefineDef ::= ‘val’ ValDef
| ‘def’ DefDef
| ‘type’ {nl} TypeDef
```

In the concrete syntax of types, refinements can contain several refined declarations.
Moreover, the refined declarations can refer to each other as well as to members of the parent type, i.e., they have access to `this`.
In the concrete syntax of types, refinements can contain several refined definitions.
They must all be abstract.
Moreover, the refined definitions can refer to each other as well as to members of the parent type, i.e., they have access to `this`.

In the internal types, each refinement defines exactly one refined declaration, and references to `this` must be made explicit in a recursive type.
In the internal types, each refinement defines exactly one refined definition, and references to `this` must be made explicit in a recursive type.

The conversion from the concrete syntax to the abstract syntax works as follows:

1. Create a fresh recursive this name ´\alpha´.
2. Replace every implicit or explicit reference to `this` in the refinement declarations by ´\alpha´.
3. Create nested [refined types](#refined-types), one for every refined declaration.
2. Replace every implicit or explicit reference to `this` in the refinement definitions by ´\alpha´.
3. Create nested [refined types](#refined-types), one for every refined definition.
4. Unless ´\alpha´ was never actually used, wrap the result in a [recursive type](#recursive-types) `{ ´\alpha´ => ´...´ }`.

### Concrete Type Lambdas
Expand Down Expand Up @@ -361,7 +362,7 @@ To each type constructor corresponds an _inferred type parameter clause_ which i

### Type Definitions

A _type definition_ ´D´ represents the right-hand-side of a `type` declaration or the bounds of a type parameter.
A _type definition_ ´D´ represents the right-hand-side of a `type` member definition or the bounds of a type parameter.
It is either:

- a type alias of the form ´= U´, or
Expand Down Expand Up @@ -465,7 +466,7 @@ If the class is monomorphic, the type designator is a value type denoting the se
Otherwise it is a type constructor with the same type parameters as the class definition.
All class types are concrete, non-stable types.

If a type designator ´p.T´ is not a class type, it refers to a type definition `T` (a type parameter or a `type` declaration) and has an _underlying [type definition](#type-definitions)_.
If a type designator ´p.T´ is not a class type, it refers to a type definition `T` (a type parameter or a `type` member definition) and has an _underlying [type definition](#type-definitions)_.
If ´p = \epsilon´ or ´p´ is a package ref, the underlying type definition is the _declared type definition_ of `T`.
Otherwise, it is determined by [`memberType`](#member-type)`(´p´, ´T´)`.
A non-class type designator is concrete (resp. stable) if and only if its underlying type definition is an alias ´U´ and ´U´ is itself concrete (resp. stable).
Expand Down Expand Up @@ -860,7 +861,7 @@ If a method name is used as a value, its type is [implicitly converted](06-expre

###### Example

The declarations
The definitions

```scala
def a: Int
Expand Down Expand Up @@ -889,7 +890,7 @@ This type represents named methods that take type arguments `´S_1, ..., S_n´`

###### Example

The declarations
The definitions

```scala
def empty[A]: List[A]
Expand Down Expand Up @@ -1030,7 +1031,7 @@ We define `memberType(´T´, ´id´, ´p´)` as follows:
- If ´T´ is a possibly parameterized class type of the form ´q.C[T_1, ..., T_n]´ (with ´n \geq 0´):
- Let ´m´ be the [class member](05-classes-and-objects.html#class-members) of ´C´ with name ´id´.
- If ´m´ is not defined, the result is undefined.
- If ´m´ is a class declaration, the result is a class result with class ´m´.
- If ´m´ is a class definition, the result is a class result with class ´m´.
- If ´m´ is a term definition in class ´D´ with declared type ´U´, the result is a term result with underlying type [`asSeenFrom`](#as-seen-from)`(´U´, ´D´, ´p´)` and stable flag true if and only if ´m´ is stable.
- If ´m´ is a type member definition in class ´D´, the result is a type result with underlying type definition [`asSeenFrom`](#as-seen-from)`(´U´, ´D´, ´p´)` where ´U´ is defined as follows:
- If ´m´ is an opaque type alias member definition with declared definition ´>: L <: H = V´, then
Expand Down
Loading

0 comments on commit b242623

Please sign in to comment.