diff --git a/spec/03-types.md b/spec/03-types.md index b4bdb7cb2e07..c523fab800b0 100644 --- a/spec/03-types.md +++ b/spec/03-types.md @@ -190,6 +190,7 @@ with a type member `Node` and the standard class `scala.Int`, SimpleType ::= SimpleType TypeArgs TypeArgs ::= ‘[’ Types ‘]’ ``` + A _parameterized type_ ´T[ T_1 , \ldots , T_n ]´ consists of a type designator ´T´ and type parameters ´T_1 , \ldots , T_n´ where @@ -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 + 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)´ @@ -626,6 +628,7 @@ c: (Int) (String, String) String ``` ### Polymorphic Method Types + A polymorphic method type is denoted internally as `[´\mathit{tps}\,´]´T´` where `[´\mathit{tps}\,´]` is a type parameter section diff --git a/spec/04-basic-declarations-and-definitions.md b/spec/04-basic-declarations-and-definitions.md index acaf2491d99b..531f1d573d1b 100644 --- a/spec/04-basic-declarations-and-definitions.md +++ b/spec/04-basic-declarations-and-definitions.md @@ -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´`. @@ -580,19 +580,22 @@ 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 @@ -600,11 +603,12 @@ A _function declaration_ has the form `def ´f\,\mathit{psig}´: ´T´`, where 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. + The type of the function body is expected to [conform](06-expressions.html#expression-typing) to the function's declared @@ -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 diff --git a/spec/05-classes-and-objects.md b/spec/05-classes-and-objects.md index 5c3a74e608a2..da1846c76e74 100644 --- a/spec/05-classes-and-objects.md +++ b/spec/05-classes-and-objects.md @@ -151,6 +151,7 @@ def delayedInit(body: => Unit): Unit ```ebnf Constr ::= AnnotType {‘(’ [Exprs] ‘)’} ``` + Constructor invocations define the type, members, and initial state of objects created by an instance creation expression, or of parts of an @@ -690,7 +691,7 @@ ClassParam ::= {Annotation} {Modifier} [(‘val’ | ‘var’)] id [‘:’ ParamType] [‘=’ Expr] ClassTemplateOpt ::= ‘extends’ ClassTemplate | [[‘extends’] TemplateBody] ``` - + The most general form of class definition is ```scala diff --git a/spec/06-expressions.md b/spec/06-expressions.md index 49687a2bf97e..ea9375e1ec23 100644 --- a/spec/06-expressions.md +++ b/spec/06-expressions.md @@ -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 +``` + +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 @@ -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`.