Skip to content

Documentation of Interweaved Clauses #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: 2.13.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions spec/03-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ with a type member `Node` and the standard class `scala.Int`,
SimpleType ::= SimpleType TypeArgs
TypeArgs ::= ‘[’ Types ‘]’
```
<!-- TODO: if currying is added for Parametrised types, change here -->

A _parameterized type_ ´T[ T_1 , \ldots , T_n ]´ consists of a type
designator ´T´ and type parameters ´T_1 , \ldots , T_n´ where
Expand Down Expand Up @@ -587,6 +588,7 @@ do they appear explicitly in programs. They are introduced in this
report as the internal types of defined identifiers.

### Method Types
<!-- TODO: Update with new internal representation for interweaving -->

A _method type_ is denoted internally as ´(\mathit{Ps})U´, where ´(\mathit{Ps})´
is a sequence of parameter names and types ´(p_1:T_1 , \ldots , p_n:T_n)´
Expand Down Expand Up @@ -626,6 +628,7 @@ c: (Int) (String, String) String
```

### Polymorphic Method Types
<!-- TODO: Update with new internal representation for interweaving -->

A polymorphic method type is denoted internally as `[´\mathit{tps}\,´]´T´` where
`[´\mathit{tps}\,´]` is a type parameter section
Expand Down
51 changes: 34 additions & 17 deletions spec/04-basic-declarations-and-definitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ TODO: Why
TODO: this is a pretty awkward description of scoping and distinctness of binders
-->

The names of all type parameters must be pairwise different in their enclosing type parameter clause. The scope of a type parameter includes in each case the whole type parameter clause. Therefore it is possible that a type parameter appears as part of its own bounds or the bounds of other type parameters in the same clause. However, a type parameter may not be bounded directly or indirectly by itself.
The names of all type parameters must be pairwise different in their enclosing type parameter clause, and between clauses if multiple are present. The scope of a type parameter includes in each case the whole type parameter clause. Therefore it is possible that a type parameter appears as part of its own bounds or the bounds of other type parameters in the same clause. However, a type parameter may not be bounded directly or indirectly by itself.

A type constructor parameter adds a nested type parameter clause to the type parameter. The most general form of a type constructor parameter is `´@a_1 \ldots @a_n \pm t[\mathit{tps}\,]´ >: ´L´ <: ´U´`.

Expand Down Expand Up @@ -580,31 +580,35 @@ on which one can write only strings.
## Function Declarations and Definitions

```ebnf
Dcl ::= ‘def’ FunDcl
FunDcl ::= FunSig ‘:’ Type
Def ::= ‘def’ FunDef
FunDef ::= FunSig [‘:’ Type] ‘=’ Expr
FunSig ::= id [FunTypeParamClause] ParamClauses
FunTypeParamClause ::= ‘[’ TypeParam {‘,’ TypeParam} ‘]’
ParamClauses ::= {ParamClause} [[nl] ‘(’ ‘implicit’ Params ‘)’]
ParamClause ::= [nl] ‘(’ [Params] ‘)’
Params ::= Param {‘,’ Param}
Param ::= {Annotation} id [‘:’ ParamType] [‘=’ Expr]
ParamType ::= Type
| ‘=>’ Type
| Type ‘*’
Dcl ::= ‘def’ FunDcl
FunDcl ::= FunSig ‘:’ Type
Def ::= ‘def’ FunDef
FunDef ::= FunSig [‘:’ Type] ‘=’ Expr
FunSig ::= id ParamClauses
ParamClauses ::= ParamClause {ParamClause}
ParamClause ::= TermParamClause | TypeParamClause | UsingParamClause
TermParamClause ::= [nl] ‘(’ [TermParams] ‘)’
TypeParamClause ::= [nl] ‘[’ TypeParams ‘]’
UsingParamClause ::= [nl] ‘(’ ‘using’ TermParams ‘)’
TermParams ::= TermParam {‘,’ TermParam}
TermParam ::= {Annotation} id [‘:’ ParamType] [‘=’ Expr]
TypeParams ::= TypeParam {‘,’ TypeParams}
TypeParam ::= Type
| ‘=>’ Type
| Type ‘*’
```

A _function declaration_ has the form `def ´f\,\mathit{psig}´: ´T´`, where
´f´ is the function's name, ´\mathit{psig}´ is its parameter
signature and ´T´ is its result type. A _function definition_
`def ´f\,\mathit{psig}´: ´T´ = ´e´` also includes a _function body_ ´e´,
i.e. an expression which defines the function's result. A parameter
signature consists of an optional type parameter clause `[´\mathit{tps}\,´]`,
followed by zero or more value parameter clauses
`(´\mathit{ps}_1´)´\ldots´(´\mathit{ps}_n´)`. Such a declaration or definition
signature consists of any interweaving of any number of: type `[´\mathit{tps}\,´]`,
term `(´\mathit{ps}´)` and using `(using ´\mathit{ps}´)` clauses,
in particular none of these clauses are required. Such a declaration or definition
introduces a value with a (possibly polymorphic) method type whose
parameter types and result type are as given.
<!-- TODO: Is this best formulation ? sort of implies def foo[T](x: Int) and def foo(x: Int)[T] are equivalent TODO: Include examples ? -->

The type of the function body is expected to [conform](06-expressions.html#expression-typing)
to the function's declared
Expand All @@ -622,6 +626,19 @@ A _value parameter clause_ ´\mathit{ps}´ consists of zero or more formal
parameter bindings such as `´x´: ´T´` or `´x: T = e´`, which bind value
parameters and associate them with their types.

Note that parameter names have to be unique not only inside clauses but between them too.
Note that parameters inside type and term clauses are allowed to depend on
parameters of the previous ones.

###### Example
```scala
def foo[T](x: T)[U >: x.type <: T][L <: List[U]](l: L): L // valid
def bar[T](x: T)[T]: String // invalid: T appears twice
def zoo(x: Int)[T, U](x: U): T // invalid: x appears twice
def aaa(x: U): U // valid if U is in scope
def bbb[T <: U](x: U)[U]: U //valid if U is in scope, same as aaa
```

### Default Arguments

Each value parameter
Expand Down
3 changes: 2 additions & 1 deletion spec/05-classes-and-objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def delayedInit(body: => Unit): Unit
```ebnf
Constr ::= AnnotType {‘(’ [Exprs] ‘)’}
```
<!-- TODO: if add constructor with interweaving, change this -->

Constructor invocations define the type, members, and initial state of
objects created by an instance creation expression, or of parts of an
Expand Down Expand Up @@ -690,7 +691,7 @@ ClassParam ::= {Annotation} {Modifier} [(‘val’ | ‘var’)]
id [‘:’ ParamType] [‘=’ Expr]
ClassTemplateOpt ::= ‘extends’ ClassTemplate | [[‘extends’] TemplateBody]
```

<!-- TODO: if update class params, change here-->
The most general form of class definition is

```scala
Expand Down
65 changes: 65 additions & 0 deletions spec/06-expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,48 @@ Type applications can be omitted if
for a polymorphic method from the types of the actual method arguments
and the expected result type.

In the case of a function with multiple lists of type arguments, and/or
which returns a value with a polymorphic function type, the applied types are the leftmost
ones, while the rightmost ones are inferred.

###### example
Where ´Z´ is an arbitrary type,
potentially containing references to ´T´ and ´U´:

```scala
def foo[T <: Int][U <: String]: Z

foo[Int][String] // valid
foo[Int] // valid*
foo // valid*

foo[String] // invalid!

// * if remaining types can be inferred
```
<!-- TODO: Shelve this ? -->
If there is need to be able to specify any combination,
an empty term clause can be used:

```scala
def foo[T <: Int]()[U <: String]: Z

foo[Int]()[String] // valid
foo[Int]() // valid*
foo() // valid*

foo()[String] // valid*

//but of course:
foo[Int][String] // invalid: expected 1 type clause, but got 2

// * if remaining types can be inferred
```

In most cases this should not be needed, and might hint at
type clauses being separated too much from the term clauses
that reference those types.

## Tuples

```ebnf
Expand Down Expand Up @@ -1798,6 +1840,29 @@ The behavior of [call-by-name parameters](#function-applications)
is preserved under eta-expansion: the corresponding actual argument expression,
a sub-expression of parameterless method type, is not evaluated in the expanded block.

In the case of a polymorphic method, the type arguments are set
according to the expected type, if they are not constrained, they are replaced by their upper bound,
even in cases where the expected type is polymorphic, leading to a typing error.
(This might however change in future versions of scala 3)

###### Examples

```scala
def id[T](x: T) = x // method type [T](T)T

val valId1 /*Any => Any*/ = id
val valId2: Int => Int = id
val valId3: [T] => T => T = id // error: Found: Any => Any, Required: [T] => T => T

def requestInt2Int(f: Int => Int) = ???

requestInt2Int(id)
requestInt2Int(valId1) // error: Found: Any => Any, Required: Int => Int
requestInt2Int(valId2)
requestInt2Int(valId3) // error: Found: [T] => T => T, Required: Int => Int // Why doesn't infer ?
requestInt2Int(valId3[Int])
```

### Dynamic Member Selection

The standard Scala library defines a marker trait `scala.Dynamic`. Subclasses of this trait are able to intercept selections and applications on their instances by defining methods of the names `applyDynamic`, `applyDynamicNamed`, `selectDynamic`, and `updateDynamic`.
Expand Down