diff --git a/docs/_spec/03-types.md b/docs/_spec/03-types.md index bbaac5de03a0..1373bc49846d 100644 --- a/docs/_spec/03-types.md +++ b/docs/_spec/03-types.md @@ -377,6 +377,565 @@ If they are all left-associative, the sequence is interpreted as ´(... (t_0 \ma The type operators `|` and `&` are not really special. Nevertheless, unless shadowed, they resolve to `scala.|` and `scala.&`, which represent [union and intersection types](#union-and-intersection-types), respectively. +### Function Types + +```ebnf +Type ::= FunTypeArgs ‘=>’ Type +FunTypeArgs ::= InfixType + | ‘(’ [ FunArgTypes ] ‘)’ + | FunParamClause +FunArgTypes ::= FunArgType { ‘,’ FunArgType } +FunArgType ::= Type + | ‘=>’ Type +FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’ +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´. + +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 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´]`. +In particular ´() \Rightarrow R´ is a shorthand for class type `scala.Function´_0´[´R´]`. + +Such class types behave as if they were instances of the following trait: + +```scala +trait Function´_n´[-´T_1´, ..., -´T_n´, +´R´]: + def apply(´x_1´: ´T_1´, ..., ´x_n´: ´T_n´): ´R´ +``` + +Their exact supertype and implementation can be consulted in the [function classes section](./12-the-scala-standard-library.md#the-function-classes) of the standard library page in this document. + +_Dependent function types_ are function types whose parameters are named and can referred to in result types. +In the concrete type ´(x_1: T_1, ..., x_n: T_n) \Rightarrow R´, ´R´ can refer to the parameters ´x_i´, notably to form path-dependent types. +It translates to the internal [refined type](#refined-types) +```scala +scala.Function´_n´[´T_1´, ..., ´T_n´, ´S´] { + def apply(´x_1´: ´T_1´, ..., ´x_n´: ´T_n´): ´R´ +} +``` +where ´S´ is the least super type of ´R´ that does not mention any of the ´x_i´. + +_Polymorphic function types_ are function types that take type arguments. +Their result type must be a function type. +In the concrete type ´[a_1 >: L_1 <: H_1, ..., a_n >: L_1 <: H_1] => (T_1, ..., T_m) => R´, the types ´T_j´ and ´R´ can refer to the type parameters ´a_i´. +It translates to the internal refined type +```scala +scala.PolyFunction { + def apply[´a_1 >: L_1 <: H_1, ..., a_n >: L_1 <: H_1´](´x_1´: ´T_1´, ..., ´x_n´: ´T_n´): ´R´ +} +``` + +### Concrete Refined Types + +```ebnf +RefinedType ::= AnnotType {[nl] Refinement} +SimpleType1 ::= ... + | Refinement +Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>> + +RefineDcl ::= ‘val’ ValDcl + | ‘def’ DefDcl + | ‘type’ {nl} TypeDcl +``` + +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 internal types, each refinement defines exactly one refined declaration, 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. +4. Unless ´\alpha´ was never actually used, wrap the result in a [recursive type](#recursive-types) `{ ´\alpha´ => ´...´ }`. + +### Concrete Type Lambdas + +```ebnf +TypeLambda ::= TypeLambdaParams ‘=>>’ Type +TypeLambdaParams ::= ‘[’ TypeLambdaParam {‘,’ TypeLambdaParam} ‘]’ +TypeLambdaParam ::= {Annotation} (id | ‘_’) [TypeParamClause] TypeBounds +TypeParamClause ::= ‘[’ VariantTypeParam {‘,’ VariantTypeParam} ‘]’ +VariantTypeParam ::= {Annotation} [‘+’ | ‘-’] (id | ‘_’) [TypeParamClause] TypeBounds +``` + +At the top level of concrete type lambda parameters, variance annotations are not allowed. +However, in internal types, all type lambda parameters have explicit variance annotations. + +When translating a concrete type lambda into an internal one, the variance of each type parameter is _inferred_ from its usages in the body of the type lambda. + +## Definitions + +From here onwards, we refer to internal types by default. + +### Kinds + +The Scala type system is fundamentally higher-kinded. +_Types_ are either _proper types_, _type constructors_ or _poly-kinded types_. + +- Proper types are the types of _terms_. +- Type constructors are type-level functions from types to types. +- Poly-kinded types can take various kinds. + +All types live in a single lattice with respect to a [_conformance_](#conformance) relationship ´<:´. +The _top type_ is `AnyKind` and the _bottom type_ is `Nothing`: all types conform to `AnyKind`, and `Nothing` conforms to all types. +They can be referred to as the standard library entities `scala.AnyKind` and `scala.Nothing`, respectively. + +Types can be _concrete_ or _abstract_. +An abstract type ´T´ always has lower and upper bounds ´L´ and ´H´ such that ´L >: T´ and ´T <: H´. +A concrete type ´T´ is considered to have itself as both lower and upper bound. + +The kind of a type is indicated by its (transitive) upper bound: + +- A type `´T <:´ scala.Any` is a proper type. +- A type `´T <: K´` where ´K´ is a [_type lambda_](#type-lambdas) (of the form `[´\pm a_1 >: L_1 <: H_1´, ..., ´\pm a_n >: L_n <: H_n´] =>> ´U´`) is a type constructor. +- Other types are poly-kinded; they are neither proper types nor type constructors. + +As a consequece, `AnyKind` itself is poly-kinded. +`Nothing` is _universally-kinded_: it has all kinds at the same time, since it conforms to all types. + +With this representation, it is rarely necessary to explicitly talk about the kinds of types. +Usually, the kinds of types are implicit through their bounds. + +Another way to look at it is that type bounds _are_ kinds. +They represent sets of types: ´>: L <: H´ denotes the set of types ´T´ such that ´L <: T´ and ´T <: H´. +A set of types can be seen as a _type of types_, i.e., as a _kind_. + +#### Conventions + +Type bounds are formally always of the form `´>: L <: H´`. +By convention, we can omit either of both bounds in writing. + +- When omitted, the lower bound ´L´ is `Nothing`. +- When omitted, the higher bound ´H´ is `Any` (_not_ `AnyKind`). + +These conventions correspond to the defaults in the concrete syntax. + +### Proper Types + +Proper types are also called _value types_, as they represent sets of _values_. + +_Stable types_ are value types that contain exactly one non-`null` value. +Stable types can be used as prefixes in named [designator types](#designator-types). +The stable types are + +- designator types referencing a stable term, +- this types, +- super types, +- literal types, +- recursive this types, and +- skolem types. + +Every stable type ´T´ is concrete and has an _underlying_ type ´U´ such that ´T <: U´. + +### Type Constructors + +To each type constructor corresponds an _inferred type parameter clause_ which is computed as follows: + +- For a [type lambda](#type-lambdas), its type parameter clause (including variance annotations). +- For a [polymorphic class type](#type-designators), the type parameter clause of the referenced class definition. +- For a non-class [type designator](#type-designators), the inferred clause of its upper bound. + +### Type Definitions + +A _type definition_ ´D´ represents the right-hand-side of a `type` declaration or the bounds of a type parameter. +It is either: + +- a type alias of the form ´= U´, or +- an abstract type definition with bounds ´>: L <: H´. + +All type definitions have a lower bound ´L´ and an upper bound ´H´, which are types. +For type aliases, ´L = H = U´. + +The type definition of a type parameter is never a type alias. + +## Types + +### Type Lambdas + +```ebnf +TypeLambda ::= ‘[‘ TypeParams ‘]‘ ‘=>>‘ Type +TypeParams ::= TypeParam {‘,‘ TypeParam} +TypeParam ::= ParamVariance id TypeBounds +ParamVariance ::= ε | ‘+‘ | ‘-‘ +``` + +A _type lambda_ of the form `[´\pm a_1 >: L_1 <: H_1´, ..., ´\pm a_n >: L_n <: H_n´] =>> ´U´` is a direct representation of a type constructor with ´n´ type parameters. +When applied to ´n´ type arguments that conform to the specified bounds, it produces another type ´U´. +Type lambdas are always concrete types. + +The scope of a type parameter extends over the result type ´U´ as well as the bounds of the type parameters themselves. + +All type constructors conform to some type lambda. + +The type bounds of the parameters of a type lambda are in contravariant position, while its result type is in covariant position. +If some type constructor `´T <:´ [´\pm a_1 >: L_1 <: H_1´, ..., ´\pm a_n >: L_n <: H_n´] =>> ´U´`, then ´T´'s ´i´th type parameter bounds contain the bounds ´>: L_i <: H_i´, and its result type conforms to ´U´. + +Note: the concrete syntax of type lambdas does not allow to specify variances for type parameters. +Instead, variances are inferred from the body of the lambda to be as general as possible. + +##### Example + +```scala +type Lst = [T] =>> List[T] // T is inferred to be covariant with bounds >: Nothing <: Any +type Fn = [A <: Seq[?], B] =>> (A => B) // A is inferred to be contravariant, B covariant + +val x: Lst[Int] = List(1) // ok, Lst[Int] expands to List[Int] +val f: Fn[List[Int], Int] = (x: List[Int]) => x.head // ok + +val g: Fn[Int, Int] = (x: Int) => x // error: Int does not conform to the bound Seq[?] + +def liftPair[F <: [T] =>> Any](f: F[Int]): Any = f +liftPair[Lst](List(1)) // ok, Lst <: ([T] =>> Any) +``` + +### Designator Types + +```ebnf +DesignatorType ::= Prefix ‘.‘ id +Prefix ::= Type + | PackageRef + | ε +PackageRef ::= id {‘.‘ id} +``` + +A designator type (or designator for short) is a reference to a definition. +Term designators refer to term definitions, while type designators refer to type definitions. + +In the abstract syntax, the `id` retains whether it is a term or type. +In the concrete syntax, an `id` refers to a *type* designator, while `id.type` refers to a *term* designator. +In that context, term designators are often called _singleton types_. + +Designators with an empty prefix ´\epsilon´ are called direct designators. +They refer to local definitions available in the scope: + +- Local `type`, `object`, `val`, `lazy val`, `var` or `def` definitions +- Term or type parameters + +The `id`s of direct designators are protected from accidental shadowing in the abstract syntax. +They retain the identity of the exact definition they refer to, rather than relying on scope-based name resolution. [^debruijnoralpha] + +[^debruijnoralpha]: In the literature, this is often achieved through De Bruijn indices or through alpha-renaming when needed. In a concrete implementation, this is often achieved through retaining *symbolic* references in a symbol table. + +The ´\epsilon´ prefix cannot be written in the concrete syntax. +A bare `id` is used instead and resolved based on scopes. + +Named designators refer to *member* definitions of a non-empty prefix: + +- Top-level definitions, including top-level classes, have a package ref prefix +- Class member definitions and refinements have a type prefix + +#### Term Designators + +A term designator ´p.x´ referring to a term definition `t` has an _underlying type_ ´U´. +If ´p = \epsilon´ or ´p´ is a package ref, the underlying type ´U´ is the _declared type_ of `t` and ´p.x´ is a stable type if an only if `t` is a `val` or `object` definition. +Otherwise, the underlying type ´U´ and whether ´p.x´ is a stable type are determined by [`memberType`](#member-type)`(´p´, ´x´)`. + +All term designators are concrete types. +If `scala.Null ´<: U´`, the term designator denotes the set of values consisting of `null` and the value denoted by ´t´, i.e., the value ´v´ for which `t eq v`. +Otherwise, the designator denotes the singleton set only containing ´v´. + +#### Type Designators + +A type designator ´p.C´ referring to a _class_ definition (including traits and hidden object classes) is a _class type_. +If the class is monomorphic, the type designator is a value type denoting the set of instances of ´C´ or any of its subclasses. +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 ´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). + +### Parameterized Types + +```ebnf +ParameterizedType ::= Type ‘[‘ TypeArgs ‘]‘ +TypeArgs ::= TypeArg {‘,‘ TypeArg} +TypeArg ::= Type + | WilcardTypeArg +WildcardTypeArg ::= ‘?‘ TypeBounds +``` + +A _parameterized type_ ´T[T_1, ..., T_n]´ consists of a type constructor ´T´ and type arguments ´T_1, ..., T_n´ where ´n \geq 1´. +The parameterized type is well-formed if + +- ´T´ is a type constructor which takes ´n´ type parameters ´a_1, ..., a_n´, i.e., it must conform to a type lambda of the form ´[\pm a_1 >: L_1 <: H_1, ..., \pm a_n >: L_n <: H_n] => U´, and +- if ´T´ is an abstract type constructor, none of the type arguments is a wildcard type argument, and +- each type argument _conforms to its bounds_, i.e., given ´\sigma´ the substitution ´[a_1 := T_1, ..., a_n := T_n]´, for each type ´i´: + - if ´T_i´ is a type and ´\sigma L_i <: T_i <: \sigma H_i´, or + - ´T_i´ is a wildcard type argument ´? >: L_{Ti} <: H_{Ti}´ and ´\sigma L_i <: L_{Ti}´ and ´H_{Ti} <: \sigma H_i´. + +´T[T_1, ..., T_n]´ is a _parameterized class type_ if and only if ´T´ is a [class type](#type-designators). +All parameterized class types are value types. + +In the concrete syntax of wildcard type arguments, if both bounds are omitted, the real bounds are inferred from the bounds of the corresponding type parameter in the target type constructor (which must be concrete). +If only one bound is omitted, `Nothing` or `Any` is used, as usual. + +#### Simplification Rules + +Wildcard type arguments used in covariant or contravariant positions can always be simplified to regular types. + +Let ´T[T_1, ..., T_n]´ be a parameterized type for a concrete type constructor. +Then, applying a wildcard type argument ´? >: L <: H´ at the ´i´'th position obeys the following equivalences: + +- If the type parameter ´T_i´ is declared covariant, then ´T[..., ? >: L <: H, ...] =:= T[..., H, ...]´. +- If the type parameter ´T_i´ is declared contravariant, then ´T[..., ? >: L <: H, ...] =:= T[..., L, ...]´. + +#### Example Parameterized Types + +Given the partial type definitions: + +```scala +class TreeMap[A <: Comparable[A], B] { ... } +class List[+A] { ... } +class I extends Comparable[I] { ... } + +class F[M[A], X] { ... } // M[A] desugars to M <: [A] =>> Any +class S[K <: String] { ... } +class G[M[Z <: I], I] { ... } // M[Z <: I] desugars to M <: [Z <: I] =>> Any +``` + +the following parameterized types are well-formed: + +```scala +TreeMap[I, String] +List[I] +List[List[Boolean]] + +F[List, Int] +F[[X] =>> List[X], Int] +G[S, String] + +List[?] // ? inferred as List[_ >: Nothing <: Any], equivalent to List[Any] +List[? <: String] // equivalent to List[String] +S[? <: String] +F[?, Boolean] // ? inferred as ? >: Nothing <: [A] =>> Any +``` + +and the following types are ill-formed: + +```scala +TreeMap[I] // illegal: wrong number of parameters +TreeMap[List[I], Int] // illegal: type parameter not within bound +List[[X] => List[X]] + +F[Int, Boolean] // illegal: Int is not a type constructor +F[TreeMap, Int] // illegal: TreeMap takes two parameters, + // F expects a constructor taking one +F[[X, Y] => (X, Y)] +G[S, Int] // illegal: S constrains its parameter to + // conform to String, + // G expects type constructor with a parameter + // that conforms to Int +``` + +The following code also contains an ill-formed type: + +```scala +trait H[F[A]]: // F[A] desugars to F <: [A] =>> Any, which is abstract + def f: F[_] // illegal : an abstract type constructor + // cannot be applied to wildcard arguments. +``` + +### This Types + +```ebnf +ThisType ::= classid ‘.‘ ‘this‘ +``` + +A _this type_ `´C´.this` denotes the `this` value of class ´C´ within ´C´. + +This types often appear implicitly as the prefix of [designator types](#designator-types) referring to members of ´C´. +They play a particular role in the type system, since they are affected by the [as seen from](#as-seen-from) operation on types. + +This types are stable types. +The underlying type of `´C´.this` is the [self type](05-classes-and-objects.html#templates) of ´C´. + +### Super Types + +```ebnf +SuperType ::= classid ‘.‘ ‘super‘ ‘[‘ classid ‘]‘ +``` + +A _super type_ `´C´.super[´D´]` denotes the `this` value of class `C` within `C`, but "widened" to only see members coming from a parent class or trait ´D´. + +Super types exist for compatibility with Scala 2, which allows shadowing of inner classes. +In a Scala 3-only context, a super type can always be replaced by the corresponding [this type](#this-types). +Therefore, we omit further discussion of super types in this specification. + +### Literal Types + +```ebnf +LiteralType ::= SimpleLiteral +``` + +A literal type `lit` denotes the single literal value `lit`. +Thus, the type ascription `1: 1` gives the most precise type to the literal value `1`: the literal type `1`. + +At run time, an expression `e` is considered to have literal type `lit` if `e == lit`. +Concretely, the result of `e.isInstanceOf[lit]` and `e match { case _ : lit => }` is determined by evaluating `e == lit`. + +Literal types are available for all primitive types, as well as for `String`. +However, only literal types for `Int`, `Long`, `Float`, `Double`, `Boolean`, `Char` and `String` can be expressed in the concrete syntax. + +Literal types are stable types. +Their underlying type is the primitive type containing their value. + +##### Example + +```scala +val x: 1 = 1 +val y: false = false +val z: false = y +val int: Int = x + +val badX: 1 = int // error: Int is not a subtype of 1 +val badY: false = true // error: true is not a subtype of false +``` + +### By-Name Types + +```ebnf +ByNameType ::= ‘=>‘ Type +``` + +A by-name type ´=> T´ denotes the declared type of a by-name term parameter. +By-name types can only appear as the types of parameters in method types, and as type arguments in [parameterized types](#parameterized-types). + + + +### Annotated Types + +```ebnf +AnnotatedType ::= Type Annotation +``` + +An _annotated type_ ´T a´ attaches the [annotation](11-annotations.html#user-defined-annotations) ´a´ to the type ´T´. + +###### Example + +The following type adds the `@suspendable` annotation to the type `String`: + +```scala +String @suspendable +``` + +### Refined Types + +```ebnf +RefinedType ::= Type ‘{‘ Refinement ‘}‘ +Refinement ::= ‘type‘ id TypeAliasOrBounds + | ‘def‘ id ‘:‘ TypeOrMethodic + | ‘val‘ id ‘:‘ Type +``` + +A _refined type_ ´T { R }´ denotes the set of values that belong to ´T´ and also have a _member_ conforming to the refinement ´R´. + +The refined type ´T { R }´ is well-formed if: + +- ´T´ is a proper type, and +- if ´R´ is a term (`def` or `val`) refinement, the refined type is a proper type, and +- if ´R´ overrides a member of ´T´, the usual rules for [overriding](05-classes-and-objects.html#overriding) apply, and +- if ´R´ is a `def` refinement with a [polymorphic method type](#polymorphic-method-types), then ´R´ overrides a member definition of ´T´. + +As an exception to the last rule, a polymorphic method type refinement is allowed if `´T <:´ scala.PolyFunction` and ´id´ is the name `apply`. + +If the refinement ´R´ overrides no member of ´T´ and is not an occurrence of the `scala.PolyFunction` exception, the refinement is said to be “structural” [^2]. + +[^2]: A reference to a structurally defined member (method call or access to a value or variable) may generate binary code that is significantly slower than an equivalent code to a non-structural member. + +Note: since a refinement does not define a _class_, it is not possible to use a [this type](#this-types) to reference term and type members of the parent type ´T´ within the refinement. +When the surface syntax of refined types makes such references, a [recursive type](#recursive-types) wraps the refined type, given access to members of self through a recursive-this type. + +###### Example + +Given the following class definitions: + +```scala +trait T: + type X <: Option[Any] + def foo: Any + def fooPoly[A](x: A): Any + +trait U extends T: + override def foo: Int + override def fooPoly[A](x: A): A + +trait V extends T + type X = Some[Int] + def bar: Int + def barPoly[A](x: A): A +``` + +We get the following conformance relationships: + +- `U <: T { def foo: Int }` +- `U <: T { def fooPoly[A](x: A): A }` +- `U <: (T { def foo: Int }) { def fooPoly[A](x: A): A }` (we can chain refined types to refine multiple members) +- `V <: T { type X <: Some[Any] }` +- `V <: T { type X >: Some[Nothing] }` +- `V <: T { type X = Some[Int] }` +- `V <: T { def bar: Any }` (a structural refinement) + +The following refined types are not well-formed: + +- `T { def barPoly[A](x: A): A }` (structural refinement for a polymorphic method type) +- `T { type X <: List[Any] }` (does not satisfy overriding rules) +- `List { def head: Int }` (the parent type `List` is not a proper type) +- `T { def foo: List }` (the refined type `List` is not a proper type) +- `T { def foo: T.this.X }` (`T.this` is not allowed outside the body of `T`) + +### Recursive Types + +```ebnf +RecursiveType ::= ‘{‘ recid ‘=>‘ Type ‘}‘ +RecursiveThis ::= recid ‘.‘ ‘this‘ +``` + +A _recursive type_ of the form `{ ´\alpha´ => ´T´ }` represents the same values as ´T´, while offering ´T´ access to its _recursive this_ type `´\alpha´`. + +Recursive types cannot directly be expressed in the concrete syntax. +They are created as needed when a refined type in the concrete syntax contains a refinement that needs access to the `this` value. +Each recursive type defines a unique self-reference `´\alpha´`, distinct from any other recursive type in the system. + +Recursive types can be unfolded during subtyping as needed, replacing references to its `´\alpha´` by a stable reference to the other side of the conformance relationship. + +##### Example + +Given the class definitions in the [refined types](#refined-types) section, we can write the following refined type in the source syntax: + +```scala +T { def foo: X } +// equivalent to +T { def foo: this.X } +``` + +This type is not directly expressible as a refined type alone, as the refinement cannot access the `this` value. +Instead, in the abstract syntax of types, it is translated to `{ ´\alpha´ => ´T´ { def foo: ´\alpha´.X } }`. + +Given the following definitions: + +```scala +trait Z extends T: + type X = Option[Int] + def foo: Option[Int] = Some(5) + +val z: Z +``` + +we can check that `z ´<:´ { ´\alpha´ => ´T´ { def foo: ´\alpha´.X } }`. +We first unfold the recursive type, substituting ´z´ for ´\alpha´, resulting in `z ´<:´ T { def foo: z.X }`. +Since the underlying type of ´z´ is ´Z´, we can resolve `z.X` to mean `Option[Int]`, and then validate that `z ´<:´ T` and that `z` has a member `def foo: Option[Int]`. + ### Union and Intersection Types Syntactically, the types `S | T` and `S & T` are infix types, where the infix operators are `|` and `&`, respectively (see above). diff --git a/docs/_spec/04-basic-declarations-and-definitions.md b/docs/_spec/04-basic-declarations-and-definitions.md index 5c45cc5c7819..a62b88673f74 100644 --- a/docs/_spec/04-basic-declarations-and-definitions.md +++ b/docs/_spec/04-basic-declarations-and-definitions.md @@ -19,8 +19,8 @@ Def ::= PatVarDef | TmplDef ``` -A _declaration_ introduces names and assigns them types. -It can form part of a [class definition](05-classes-and-objects.html#templates) or of a refinement in a [compound type](03-types.html#compound-types). +A _declaration_ introduces names and assigns them types or type definitions. +It can form part of a [class definition](05-classes-and-objects.html#templates) or of a refinement in a [refined type](03-types.html#concrete-refined-types). A _definition_ introduces names that denote terms or types. It can form part of an object or class definition or it can be local to a block. @@ -61,11 +61,11 @@ PatDef ::= Pattern2 {‘,’ Pattern2} [‘:’ Type] ‘=’ Expr ids ::= id {‘,’ id} ``` -A value declaration `val ´x´: ´T´` introduces ´x´ as a name of a value of type ´T´. +A value declaration `val ´x´: ´T´` introduces ´x´ as a name of a value of _declared type_ ´T´. A value definition `val ´x´: ´T´ = ´e´` defines ´x´ as a name of the value that results from the evaluation of ´e´. -If the value definition is not recursive, the type ´T´ may be omitted, in which case the [packed type](06-expressions.html#expression-typing) of expression ´e´ is assumed. -If a type ´T´ is given, then ´e´ is expected to conform to it. +If the value definition is not recursive, the declared type ´T´ may be omitted, in which case the [packed type](06-expressions.html#expression-typing) of expression ´e´ is assumed. +If a type ´T´ is given, then it must be a [proper type](03-types.html#proper-types) and ´e´ is expected to [conform to it](06-expressions.html#expression-typing). Evaluation of the value definition implies evaluation of its right-hand side ´e´, unless it has the modifier `lazy`. The effect of the value definition is to bind ´x´ to the value of ´e´ @@ -156,7 +156,7 @@ An implementation of a class may _define_ a declared variable using a variable d A variable definition `var ´x´: ´T´ = ´e´` introduces a mutable variable with type ´T´ and initial value as given by the expression ´e´. The type ´T´ can be omitted, in which case the type of ´e´ is assumed. -If ´T´ is given, then ´e´ is expected to [conform to it](06-expressions.html#expression-typing). +If ´T´ is given, then it must be a [proper type](03-types.html#proper-types) and ´e´ is expected to [conform to it](06-expressions.html#expression-typing). Variable definitions can alternatively have a [pattern](08-pattern-matching.html#patterns) as left-hand side. A variable definition `var ´p´ = ´e´` where ´p´ is a pattern other than a simple name or a name followed by a colon and a type is expanded in the same way as a [value definition](#value-declarations-and-definitions) `val ´p´ = ´e´`, except that the free names in ´p´ are introduced as mutable variables, not values. @@ -217,8 +217,6 @@ A variable definition `var ´x_1, ..., x_n: T´ = ´e´` is a shorthand for the ## Type Declarations and Type Aliases - - ```ebnf Dcl ::= ‘type’ {nl} TypeDcl TypeDcl ::= id [TypeParamClause] [‘>:’ Type] [‘<:’ Type] @@ -226,32 +224,48 @@ Def ::= ‘type’ {nl} TypeDef TypeDef ::= id [TypeParamClause] ‘=’ Type ``` +A possibly parameterized _type declaration_ `type ´t´[´\mathit{tps}\,´] >: ´L´ <: ´H´` declares ´t´ to be an abstract type. +If omitted, ´L´ and ´H´ are implied to be `Nothing` and `scala.Any`, respectively. + +A possibly parameterized _type alias_ `type ´t´[´\mathit{tps}\,´] = ´T´` defines ´t´ to be a concrete type member. + +If a type parameter clause `[´\mathit{tps}\,´]` is present, it is desugared away according to the rules in the following section. + ### Desugaring of parameterized type declarations -A parameterized type declaration is desugared into an unparameterized type declaration -whose bounds are type lambdas with explicit variance annotations. + +A parameterized type declaration is desugared into an unparameterized type declaration whose bounds are [type lambdas](03-types.html#type-lambdas) with explicit variance annotations. + +The scope of a type parameter extends over the bounds `>: ´L´ <: ´U´` or the alias `= ´T´` and the type parameter clause ´\mathit{tps}´ itself. +A higher-order type parameter clause (of an abstract type constructor ´tc´) has the same kind of scope, restricted to the declaration of the type parameter ´tc´. + +To illustrate nested scoping, these declarations are all equivalent: `type t[m[x] <: Bound[x], Bound[x]]`, `type t[m[x] <: Bound[x], Bound[y]]` and `type t[m[x] <: Bound[x], Bound[_]]`, as the scope of, e.g., the type parameter of ´m´ is limited to the declaration of ´m´. +In all of them, ´t´ is an abstract type member that abstracts over two type constructors: ´m´ stands for a type constructor that takes one type parameter and that must be a subtype of `Bound`, ´t´'s second type constructor parameter. +`t[MutableList, Iterable]` is a valid use of ´t´. #### Abstract Type -An abstract type + +A parameterized abstract type ```scala -type ´t´[´\mathit{tps}\,´] >: ´L´ <: ´U´ +type ´t´[´\mathit{tps}\,´] >: ´L´ <: ´H´ ``` is desugared into an unparameterized abstract type as follow: - If `L` conforms to `Nothing`, then, ```scala type ´t´ >: Nothing - <: [´\mathit{tps'}\,´] =>> ´U´ + <: [´\mathit{tps'}\,´] =>> ´H´ ``` - otherwise, ```scala type ´t´ >: [´\mathit{tps'}\,´] =>> ´L´ - <: [´\mathit{tps'}\,´] =>> ´U´ + <: [´\mathit{tps'}\,´] =>> ´H´ ``` - -If at least one of the ´\mathit{tps}´ contains an explicit variance annotation, then ´\mathit{tps'} = \mathit{tps}´, otherwise we infer the variance of each type parameter as with the user-written type lambda `[´\mathit{tps}\,´] =>> ´U´`. -The same desugaring applies to type parameters. For instance, +If at least one of the ´\mathit{tps}´ contains an explicit variance annotation, then ´\mathit{tps'} = \mathit{tps}´, otherwise we infer the variance of each type parameter as with the user-written type lambda `[´\mathit{tps}\,´] =>> ´H´`. + +The same desugaring applies to type parameters. +For instance, ```scala [F[X] <: Coll[X]] ``` @@ -261,6 +275,7 @@ is treated as a shorthand for ``` #### Type Alias + A parameterized type alias ```scala type ´t´[´\mathit{tps}\,´] = ´T´ @@ -271,34 +286,17 @@ type ´t´ = [´\mathit{tps'}\,´] =>> ´T´ ``` where ´\mathit{tps'}´ is computed as in the previous case. -´\color{red}{\text{TODO SCALA3: Everything else in this section (and the next one -on type parameters) needs to be rewritten to take into account the desugaring described above.}}´ +### Non-Parameterized Type Declarations and Type Aliases -A _type declaration_ `type ´t´[´\mathit{tps}\,´] >: ´L´ <: ´U´` declares ´t´ to be an abstract type with lower bound type ´L´ and upper bound type ´U´. -If the type parameter clause `[´\mathit{tps}\,´]` is omitted, ´t´ abstracts over a proper type, otherwise ´t´ stands for a type constructor that accepts type arguments as described by the type parameter clause. +A _type declaration_ `type ´t´ >: ´L´ <: ´H´` declares ´t´ to be an abstract type whose [type definition](03-types.html#type-definitions) has the lower bound type ´L´ and upper bound type ´H´. -If a type declaration appears as a member declaration of a type, implementations of the type may implement ´t´ with any type ´T´ for which ´L <: T <: U´. -It is a compile-time error if ´L´ does not conform to ´U´. -Either or both bounds may be omitted. -If the lower bound ´L´ is absent, the bottom type `scala.Nothing` is assumed. -If the upper bound ´U´ is absent, the top type `scala.Any` is assumed. - -A type constructor declaration imposes additional restrictions on the concrete types for which ´t´ may stand. -Besides the bounds ´L´ and ´U´, the type parameter clause may impose higher-order bounds and variances, as governed by the [conformance of type constructors](03-types.html#conformance). - -The scope of a type parameter extends over the bounds `>: ´L´ <: ´U´` and the type parameter clause ´\mathit{tps}´ itself. -A higher-order type parameter clause (of an abstract type constructor ´tc´) has the same kind of scope, restricted to the declaration of the type parameter ´tc´. - -To illustrate nested scoping, these declarations are all equivalent: `type t[m[x] <: Bound[x], Bound[x]]`, `type t[m[x] <: Bound[x], Bound[y]]` and `type t[m[x] <: Bound[x], Bound[_]]`, as the scope of, e.g., the type parameter of ´m´ is limited to the declaration of ´m´. -In all of them, ´t´ is an abstract type member that abstracts over two type constructors: ´m´ stands for a type constructor that takes one type parameter and that must be a subtype of ´Bound´, ´t´'s second type constructor parameter. -`t[MutableList, Iterable]` is a valid use of ´t´. +If a type declaration appears as a member declaration of a type, implementations of the type may implement ´t´ with any type ´T´ for which ´L <: T <: H´. +It is a compile-time error if ´L´ does not conform to ´H´. A _type alias_ `type ´t´ = ´T´` defines ´t´ to be an alias name for the type ´T´. -The left hand side of a type alias may have a type parameter clause, e.g. `type ´t´[´\mathit{tps}\,´] = ´T´`. -The scope of a type parameter extends over the right hand side ´T´ and the type parameter clause ´\mathit{tps}´ itself. -The scope rules for [definitions](#basic-declarations-and-definitions) and [type parameters](#method-declarations-and-definitions) make it possible that a type name appears in its own bound or in its right-hand side. -However, it is a static error if a type alias refers recursively to the defined type constructor itself. +The scope rules for [definitions](#basic-declarations-and-definitions) and [type parameters](#method-declarations-and-definitions) make it possible that a type name appears in its own bounds or in its right-hand side. +However, it is a static error if a type alias refers recursively to the defined type itself. That is, the type ´T´ in a type alias `type ´t´[´\mathit{tps}\,´] = ´T´` may not refer directly or indirectly to the name ´t´. It is also an error if an abstract type is directly or indirectly its own upper or lower bound. @@ -309,8 +307,8 @@ The following are legal type declarations and definitions: ```scala type IntList = List[Integer] type T <: Comparable[T] -type Two[A] = Tuple2[A, A] -type MyCollection[+X] <: Iterable[X] +type Two[A] = Tuple2[A, A] // desugars to Two = [A] =>> Tuple2[A, A] +type MyCollection[+X] <: Iterable[X] // desugars to MyCollection <: [+X] =>> Iterable[X] ``` The following are illegal: @@ -323,11 +321,11 @@ type T <: S type T >: Comparable[T.That] // Cannot select from T. // T is a type, not a value -type MyCollection <: Iterable // Type constructor members must explicitly - // state their type parameters. +type MyCollection <: Iterable // The reference to the type constructor + // Iterable must explicitly state its type arguments. ``` -If a type alias `type ´t´[´\mathit{tps}\,´] = ´S´` refers to a class type ´S´, the name ´t´ can also be used as a constructor for objects of type ´S´. +If a type alias `type ´t´ = ´S´` refers to a class type ´S´ (or to a type lambda that is the eta-expansion of class type ´S´), the name ´t´ can also be used as a constructor for objects of type ´S´. ###### Example @@ -432,14 +430,12 @@ The variance position changes at the following constructs. - The variance position of the lower bound of a type declaration or type parameter is the opposite of the variance position of the type declaration or parameter. - The type of a mutable variable is always in invariant position. - The right-hand side of a type alias is always in invariant position. -- The prefix ´S´ of a type selection `´S´#´T´` is always in invariant position. -- For a type argument ´T´ of a type `´S´[´... T ...´ ]`: -If the corresponding type parameter is invariant, then ´T´ is in invariant position. -If the corresponding type parameter is contravariant, the variance position of ´T´ is the opposite of the variance position of the enclosing type `´S´[´... T ...´ ]`. - - +- The prefix ´p´ of a type selection `´p.T´` is always in invariant position. +- For a type argument ´T´ of a type `´S´[´..., T, ...´]`: + - If the corresponding type parameter of ´S´ is invariant, then ´T´ is in invariant position. + - If the corresponding type parameter of ´S´ is contravariant, the variance position of ´T´ is the opposite of the variance position of the enclosing type `´S´[´..., T, ...´]`. -References to the type parameters in [object-private or object-protected values, types, variables, or methods](05-classes-and-objects.html#modifiers) of the class are not checked for their variance position. +References to the type parameters in [object-private values, types, variables, or methods](05-classes-and-objects.html#modifiers) of the class are not checked for their variance position. In these members the type parameter may appear anywhere without restricting its legal variance annotations. ###### Example @@ -447,7 +443,8 @@ The following variance annotation is legal. ```scala abstract class P[+A, +B] { - def fst: A; def snd: B + def fst: A + def snd: B } ``` @@ -471,14 +468,14 @@ If the mutable variables are object-private, the class definition becomes legal ```scala abstract class R[+A, +B](x: A, y: B) { - private[this] var fst: A = x // OK - private[this] var snd: B = y // OK + private var fst: A = x // OK + private var snd: B = y // OK } ``` ###### Example -The following variance annotation is illegal, since ´a´ appears in contravariant position in the parameter of `append`: +The following variance annotation is illegal, since ´A´ appears in contravariant position in the parameter of `append`: ```scala abstract class Sequence[+A] { @@ -591,7 +588,7 @@ ParamType ::= ‘=>’ Type ``` The type of a value parameter may be prefixed by `=>`, e.g. `´x´: => ´T´`. -The type of such a parameter is then the parameterless method type `=> ´T´`. +The type of such a parameter is then the [by-name type](./03-types.html#by-name-types) `=> ´T´`. This indicates that the corresponding argument is not evaluated at the point of method application, but instead is evaluated at each use within the method. That is, the argument is evaluated using _call-by-name_.