diff --git a/docs/_docs/internals/syntax-3.1.md b/docs/_docs/internals/syntax-3.1.md index 4d4d3b6d858d..0104222f50f5 100644 --- a/docs/_docs/internals/syntax-3.1.md +++ b/docs/_docs/internals/syntax-3.1.md @@ -11,7 +11,7 @@ hexadecimal code: ```ebnf UnicodeEscape ::= ‘\’ ‘u’ {‘u’} hexDigit hexDigit hexDigit hexDigit -hexDigit ::= ‘0’ | … | ‘9’ | ‘A’ | … | ‘F’ | ‘a’ | … | ‘f’ +hexDigit ::= ‘0’ | ... | ‘9’ | ‘A’ | ... | ‘F’ | ‘a’ | ... | ‘f’ ``` Informal descriptions are typeset as `“some comment”`. @@ -22,15 +22,15 @@ form. ```ebnf whiteSpace ::= ‘\u0020’ | ‘\u0009’ | ‘\u000D’ | ‘\u000A’ -upper ::= ‘A’ | … | ‘Z’ | ‘\$’ | ‘_’ “… and Unicode category Lu” -lower ::= ‘a’ | … | ‘z’ “… and Unicode category Ll” -letter ::= upper | lower “… and Unicode categories Lo, Lt, Lm, Nl” -digit ::= ‘0’ | … | ‘9’ +upper ::= ‘A’ | ... | ‘Z’ | ‘\$’ | ‘_’ “... and Unicode category Lu” +lower ::= ‘a’ | ... | ‘z’ “... and Unicode category Ll” +letter ::= upper | lower “... and Unicode categories Lo, Lt, Lm, Nl” +digit ::= ‘0’ | ... | ‘9’ paren ::= ‘(’ | ‘)’ | ‘[’ | ‘]’ | ‘{’ | ‘}’ | ‘'(’ | ‘'[’ | ‘'{’ delim ::= ‘`’ | ‘'’ | ‘"’ | ‘.’ | ‘;’ | ‘,’ opchar ::= ‘!’ | ‘#’ | ‘%’ | ‘&’ | ‘*’ | ‘+’ | ‘-’ | ‘/’ | ‘:’ | ‘<’ | ‘=’ | ‘>’ | ‘?’ | ‘@’ | ‘\’ | ‘^’ | ‘|’ | ‘~’ - “… and Unicode categories Sm, So” + “... and Unicode categories Sm, So” printableChar ::= “all characters in [\u0020, \u007E] inclusive” charEscapeSeq ::= ‘\’ (‘b’ | ‘t’ | ‘n’ | ‘f’ | ‘r’ | ‘"’ | ‘'’ | ‘\’) @@ -49,7 +49,7 @@ integerLiteral ::= (decimalNumeral | hexNumeral) [‘L’ | ‘l’] decimalNumeral ::= ‘0’ | nonZeroDigit {digit} hexNumeral ::= ‘0’ (‘x’ | ‘X’) hexDigit {hexDigit} digit ::= ‘0’ | nonZeroDigit -nonZeroDigit ::= ‘1’ | … | ‘9’ +nonZeroDigit ::= ‘1’ | ... | ‘9’ floatingPointLiteral ::= digit {digit} ‘.’ {digit} [exponentPart] [floatType] diff --git a/docs/_docs/internals/syntax.md b/docs/_docs/internals/syntax.md index 445e86ee2408..c4e71ad11612 100644 --- a/docs/_docs/internals/syntax.md +++ b/docs/_docs/internals/syntax.md @@ -20,51 +20,46 @@ productions map to AST nodes. The following description of Scala tokens uses literal characters `‘c’` when referring to the ASCII fragment `\u0000` – `\u007F`. -_Unicode escapes_ are used to represent the [Unicode character](https://www.w3.org/International/articles/definitions-characters/) with the given -hexadecimal code: - -```ebnf -UnicodeEscape ::= ‘\’ ‘u’ {‘u’} hexDigit hexDigit hexDigit hexDigit -hexDigit ::= ‘0’ | … | ‘9’ | ‘A’ | … | ‘F’ | ‘a’ | … | ‘f’ -``` - -Informal descriptions are typeset as `“some comment”`. - ## Lexical Syntax -The lexical syntax of Scala is given by the following grammar in EBNF -form. +The lexical syntax of Scala is given by the following grammar in EBNF form: ```ebnf whiteSpace ::= ‘\u0020’ | ‘\u0009’ | ‘\u000D’ | ‘\u000A’ -upper ::= ‘A’ | … | ‘Z’ | ‘\$’ | ‘_’ “… and Unicode category Lu” -lower ::= ‘a’ | … | ‘z’ “… and Unicode category Ll” -letter ::= upper | lower “… and Unicode categories Lo, Lt, Lm, Nl” -digit ::= ‘0’ | … | ‘9’ +upper ::= ‘A’ | ... | ‘Z’ | ‘$’ and any character in Unicode categories Lu, Lt or Nl, + and any character in Unicode categories Lo and Lm that doesn't have + contributory property Other_Lowercase +lower ::= ‘a’ | ... | ‘z’ | ‘_’ and any character in Unicode category Ll, + and any character in Unicode categories Lo or Lm that has contributory + property Other_Lowercase +letter ::= upper | lower +digit ::= ‘0’ | ... | ‘9’ paren ::= ‘(’ | ‘)’ | ‘[’ | ‘]’ | ‘{’ | ‘}’ delim ::= ‘`’ | ‘'’ | ‘"’ | ‘.’ | ‘;’ | ‘,’ opchar ::= ‘!’ | ‘#’ | ‘%’ | ‘&’ | ‘*’ | ‘+’ | ‘-’ | ‘/’ | ‘:’ | ‘<’ | ‘=’ | ‘>’ | ‘?’ | ‘@’ | ‘\’ | ‘^’ | ‘|’ | ‘~’ - “… and Unicode categories Sm, So” -printableChar ::= “all characters in [\u0020, \u007E] inclusive” + and any character in Unicode categories Sm or So +printableChar ::= all characters in [\u0020, \u007E] inclusive +UnicodeEscape ::= ‘\’ ‘u’ {‘u’} hexDigit hexDigit hexDigit hexDigit +hexDigit ::= ‘0’ | ... | ‘9’ | ‘A’ | ... | ‘F’ | ‘a’ | ... | ‘f’ charEscapeSeq ::= ‘\’ (‘b’ | ‘t’ | ‘n’ | ‘f’ | ‘r’ | ‘"’ | ‘'’ | ‘\’) +escapeSeq ::= UnicodeEscape | charEscapeSeq op ::= opchar {opchar} varid ::= lower idrest -alphaid ::= upper idrest - | varid +boundvarid ::= varid + | ‘`’ varid ‘`’ plainid ::= alphaid | op id ::= plainid - | ‘`’ { charNoBackQuoteOrNewline | UnicodeEscape | charEscapeSeq } ‘`’ + | ‘`’ { charNoBackQuoteOrNewline | escapeSeq } ‘`’ idrest ::= {letter | digit} [‘_’ op] quoteId ::= ‘'’ alphaid spliceId ::= ‘$’ alphaid ; integerLiteral ::= (decimalNumeral | hexNumeral) [‘L’ | ‘l’] -decimalNumeral ::= ‘0’ | nonZeroDigit [{digit | ‘_’} digit] +decimalNumeral ::= ‘0’ | digit [{digit | ‘_’} digit] hexNumeral ::= ‘0’ (‘x’ | ‘X’) hexDigit [{hexDigit | ‘_’} hexDigit] -nonZeroDigit ::= ‘1’ | … | ‘9’ floatingPointLiteral ::= [decimalNumeral] ‘.’ digit [{digit | ‘_’} digit] [exponentPart] [floatType] @@ -75,25 +70,25 @@ floatType ::= ‘F’ | ‘f’ | ‘D’ | ‘d’ booleanLiteral ::= ‘true’ | ‘false’ -characterLiteral ::= ‘'’ (printableChar | charEscapeSeq) ‘'’ +characterLiteral ::= ‘'’ (charNoQuoteOrNewline | escapeSeq) ‘'’ stringLiteral ::= ‘"’ {stringElement} ‘"’ | ‘"""’ multiLineChars ‘"""’ -stringElement ::= printableChar \ (‘"’ | ‘\’) - | UnicodeEscape - | charEscapeSeq -multiLineChars ::= {[‘"’] [‘"’] char \ ‘"’} {‘"’} -processedStringLiteral - ::= alphaid ‘"’ {[‘\’] processedStringPart | ‘\\’ | ‘\"’} ‘"’ - | alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘$’) | escape} {‘"’} ‘"""’ -processedStringPart +stringElement ::= charNoDoubleQuoteOrNewline + | escapeSeq +multiLineChars ::= {[‘"’] [‘"’] charNoDoubleQuote} {‘"’} + +interpolatedString + ::= alphaid ‘"’ {[‘\’] interpolatedStringPart | ‘\\’ | ‘\"’} ‘"’ + | alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘\$’) | escape} {‘"’} ‘"""’ +interpolatedStringPart ::= printableChar \ (‘"’ | ‘$’ | ‘\’) | escape -escape ::= ‘$$’ - | ‘$’ letter { letter | digit } - | ‘{’ Block [‘;’ whiteSpace stringFormat whiteSpace] ‘}’ -stringFormat ::= {printableChar \ (‘"’ | ‘}’ | ‘ ’ | ‘\t’ | ‘\n’)} - -symbolLiteral ::= ‘'’ plainid // until 2.13 +escape ::= ‘\$\$’ + | ‘\$"’ + | ‘\$’ alphaid + | ‘\$’ BlockExpr +alphaid ::= upper idrest + | varid comment ::= ‘/*’ “any sequence of characters; nested comments are allowed” ‘*/’ | ‘//’ “any sequence of characters up to end of line” @@ -159,7 +154,7 @@ SimpleLiteral ::= [‘-’] integerLiteral | characterLiteral | stringLiteral Literal ::= SimpleLiteral - | processedStringLiteral + | interpolatedStringLiteral | symbolLiteral | ‘null’ diff --git a/docs/_docs/reference/changed-features/overload-resolution.md b/docs/_docs/reference/changed-features/overload-resolution.md index bd7782ded520..621515c2a7f8 100644 --- a/docs/_docs/reference/changed-features/overload-resolution.md +++ b/docs/_docs/reference/changed-features/overload-resolution.md @@ -66,11 +66,11 @@ as follows: Replace the sentence -> Otherwise, let `S1,…,Sm` be the vector of types obtained by typing each argument with an undefined expected type. +> Otherwise, let `S1,...,Sm` be the vector of types obtained by typing each argument with an undefined expected type. with the following paragraph: -> Otherwise, let `S1,…,Sm` be the vector of known types of all argument types, where the _known type_ of an argument `E` +> Otherwise, let `S1,...,Sm` be the vector of known types of all argument types, where the _known type_ of an argument `E` is determined as followed: - If `E` is a function value `(p_1, ..., p_n) => B` that misses some parameter types, the known type diff --git a/docs/_docs/reference/syntax.md b/docs/_docs/reference/syntax.md index 6abc3b2011d1..dd2e7ce118c4 100644 --- a/docs/_docs/reference/syntax.md +++ b/docs/_docs/reference/syntax.md @@ -21,51 +21,48 @@ productions map to AST nodes. The following description of Scala tokens uses literal characters `‘c’` when referring to the ASCII fragment `\u0000` – `\u007F`. -_Unicode escapes_ are used to represent the [Unicode character](https://www.w3.org/International/articles/definitions-characters/) with the given -hexadecimal code: - -``` -UnicodeEscape ::= ‘\’ ‘u’ {‘u’} hexDigit hexDigit hexDigit hexDigit -hexDigit ::= ‘0’ | … | ‘9’ | ‘A’ | … | ‘F’ | ‘a’ | … | ‘f’ -``` - Informal descriptions are typeset as `“some comment”`. ## Lexical Syntax -The lexical syntax of Scala is given by the following grammar in EBNF -form. +The lexical syntax of Scala is given by the following grammar in EBNF form: -``` +```ebnf whiteSpace ::= ‘\u0020’ | ‘\u0009’ | ‘\u000D’ | ‘\u000A’ -upper ::= ‘A’ | … | ‘Z’ | ‘\$’ | ‘_’ “… and Unicode category Lu” -lower ::= ‘a’ | … | ‘z’ “… and Unicode category Ll” -letter ::= upper | lower “… and Unicode categories Lo, Lt, Nl” -digit ::= ‘0’ | … | ‘9’ +upper ::= ‘A’ | ... | ‘Z’ | ‘$’ and any character in Unicode categories Lu, Lt or Nl, + and any character in Unicode categories Lo and Lm that doesn't have + contributory property Other_Lowercase +lower ::= ‘a’ | ... | ‘z’ | ‘_’ and any character in Unicode category Ll, + and any character in Unicode categories Lo or Lm that has contributory + property Other_Lowercase +letter ::= upper | lower +digit ::= ‘0’ | ... | ‘9’ paren ::= ‘(’ | ‘)’ | ‘[’ | ‘]’ | ‘{’ | ‘}’ delim ::= ‘`’ | ‘'’ | ‘"’ | ‘.’ | ‘;’ | ‘,’ opchar ::= ‘!’ | ‘#’ | ‘%’ | ‘&’ | ‘*’ | ‘+’ | ‘-’ | ‘/’ | ‘:’ | ‘<’ | ‘=’ | ‘>’ | ‘?’ | ‘@’ | ‘\’ | ‘^’ | ‘|’ | ‘~’ - “… and Unicode categories Sm, So” -printableChar ::= “all characters in [\u0020, \u007E] inclusive” + and any character in Unicode categories Sm or So +printableChar ::= all characters in [\u0020, \u007E] inclusive +UnicodeEscape ::= ‘\’ ‘u’ {‘u’} hexDigit hexDigit hexDigit hexDigit +hexDigit ::= ‘0’ | ... | ‘9’ | ‘A’ | ... | ‘F’ | ‘a’ | ... | ‘f’ charEscapeSeq ::= ‘\’ (‘b’ | ‘t’ | ‘n’ | ‘f’ | ‘r’ | ‘"’ | ‘'’ | ‘\’) +escapeSeq ::= UnicodeEscape | charEscapeSeq op ::= opchar {opchar} varid ::= lower idrest -alphaid ::= upper idrest - | varid +boundvarid ::= varid + | ‘`’ varid ‘`’ plainid ::= alphaid | op id ::= plainid - | ‘`’ { charNoBackQuoteOrNewline | UnicodeEscape | charEscapeSeq } ‘`’ + | ‘`’ { charNoBackQuoteOrNewline | escapeSeq } ‘`’ idrest ::= {letter | digit} [‘_’ op] quoteId ::= ‘'’ alphaid spliceId ::= ‘$’ alphaid ; integerLiteral ::= (decimalNumeral | hexNumeral) [‘L’ | ‘l’] -decimalNumeral ::= ‘0’ | nonZeroDigit [{digit | ‘_’} digit] +decimalNumeral ::= ‘0’ | digit [{digit | ‘_’} digit] hexNumeral ::= ‘0’ (‘x’ | ‘X’) hexDigit [{hexDigit | ‘_’} hexDigit] -nonZeroDigit ::= ‘1’ | … | ‘9’ floatingPointLiteral ::= [decimalNumeral] ‘.’ digit [{digit | ‘_’} digit] [exponentPart] [floatType] @@ -76,25 +73,25 @@ floatType ::= ‘F’ | ‘f’ | ‘D’ | ‘d’ booleanLiteral ::= ‘true’ | ‘false’ -characterLiteral ::= ‘'’ (printableChar | charEscapeSeq) ‘'’ +characterLiteral ::= ‘'’ (charNoQuoteOrNewline | escapeSeq) ‘'’ stringLiteral ::= ‘"’ {stringElement} ‘"’ | ‘"""’ multiLineChars ‘"""’ -stringElement ::= printableChar \ (‘"’ | ‘\’) - | UnicodeEscape - | charEscapeSeq -multiLineChars ::= {[‘"’] [‘"’] char \ ‘"’} {‘"’} -processedStringLiteral - ::= alphaid ‘"’ {[‘\’] processedStringPart | ‘\\’ | ‘\"’} ‘"’ - | alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘$’) | escape} {‘"’} ‘"""’ -processedStringPart +stringElement ::= charNoDoubleQuoteOrNewline + | escapeSeq +multiLineChars ::= {[‘"’] [‘"’] charNoDoubleQuote} {‘"’} + +interpolatedString + ::= alphaid ‘"’ {[‘\’] interpolatedStringPart | ‘\\’ | ‘\"’} ‘"’ + | alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘\$’) | escape} {‘"’} ‘"""’ +interpolatedStringPart ::= printableChar \ (‘"’ | ‘$’ | ‘\’) | escape -escape ::= ‘$$’ - | ‘$’ letter { letter | digit } - | ‘{’ Block [‘;’ whiteSpace stringFormat whiteSpace] ‘}’ -stringFormat ::= {printableChar \ (‘"’ | ‘}’ | ‘ ’ | ‘\t’ | ‘\n’)} - -symbolLiteral ::= ‘'’ plainid // until 2.13 +escape ::= ‘\$\$’ + | ‘\$"’ + | ‘\$’ alphaid + | ‘\$’ BlockExpr +alphaid ::= upper idrest + | varid comment ::= ‘/*’ “any sequence of characters; nested comments are allowed” ‘*/’ | ‘//’ “any sequence of characters up to end of line” @@ -163,7 +160,7 @@ SimpleLiteral ::= [‘-’] integerLiteral | characterLiteral | stringLiteral Literal ::= SimpleLiteral - | processedStringLiteral + | interpolatedStringLiteral | symbolLiteral | ‘null’ diff --git a/docs/_spec/01-lexical-syntax.md b/docs/_spec/01-lexical-syntax.md index e2470e27d2e0..de11de10402f 100644 --- a/docs/_spec/01-lexical-syntax.md +++ b/docs/_spec/01-lexical-syntax.md @@ -20,6 +20,28 @@ To construct tokens, characters are distinguished according to the following cla 1. Delimiter characters ``‘`’ | ‘'’ | ‘"’ | ‘.’ | ‘;’ | ‘,’ ``. 1. Operator characters. These consist of all printable ASCII characters (`\u0020` - `\u007E`) that are in none of the sets above, mathematical symbols (`Sm`) and other symbols (`So`). +## Optional Braces + +The principle of optional braces is that any keyword that can be followed by `{` can also be followed by an indented block, without needing an intervening `:`. +(Allowing an optional `:` would be counterproductive since it would introduce several ways to do the same thing.) + +The lexical analyzer inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](./other-new-features/indentation.md). + +´\color{red}{\text{TODO SCALA3: Port soft-modifier.md and link it here.}}´ + +In the context-free productions below we use the notation `<<< ts >>>` to indicate a token sequence `ts` that is either enclosed in a pair of braces `{ ts }` or that constitutes an indented region `indent ts outdent`. +Analogously, the notation `:<<< ts >>>` indicates a token sequence `ts` that is either enclosed in a pair of braces `{ ts }` or that constitutes an indented region `indent ts outdent` that follows a `colon` token. + +A `colon` token reads as the standard colon "`:`" but is generated instead of it where `colon` is legal according to the context free syntax, but only if the previous token is an alphanumeric identifier, a backticked identifier, or one of the tokens `this`, `super`, `new`, "`)`", and "`]`". + +``` +colon ::= ':' -- with side conditions explained above + <<< ts >>> ::= ‘{’ ts ‘}’ + | indent ts outdent +:<<< ts >>> ::= [nl] ‘{’ ts ‘}’ + | colon indent ts outdent +``` + ## Identifiers ```ebnf @@ -27,8 +49,9 @@ op ::= opchar {opchar} varid ::= lower idrest boundvarid ::= varid | ‘`’ varid ‘`’ -plainid ::= upper idrest - | varid +alphaid ::= upper idrest + | varid +plainid ::= alphaid | op id ::= plainid | ‘`’ { charNoBackQuoteOrNewline | escapeSeq } ‘`’ @@ -79,28 +102,30 @@ Some examples of constant identifiers are The ‘$’ character is reserved for compiler-synthesized identifiers. User programs should not define identifiers that contain ‘$’ characters. +### Regular keywords + The following names are reserved words instead of being members of the syntactic class `id` of lexical identifiers. ```scala -abstract case catch class def -do else extends false final -finally for forSome if implicit -import lazy macro match new -null object override package private -protected return sealed super this -throw trait try true type -val var while with yield -_ : = => <- <: <% >: # @ +abstract case catch class def do else +enum export extends false final finally for +given if implicit import lazy match new +null object override package private protected return +sealed super then throw trait true try +type val var while with yield +: = <- => <: >: # +@ =>> ?=> ``` -The Unicode operators `\u21D2` ‘´\Rightarrow´’ and `\u2190` ‘´\leftarrow´’, which have the ASCII equivalents `=>` and `<-`, are also reserved. +### Soft keywords -> Here are examples of identifiers: -> ```scala -> x Object maxIndex p2p empty_? -> + `yield` αρετη _y dot_product_* -> __system _MAX_LEN_ -> ``` +Additionally, the following soft keywords are reserved only in some situations. + +´\color{red}{\text{TODO SCALA3: Port soft-modifier.md and link it here.}}´ + +``` +as derives end extension infix inline opaque open transparent using | * + - +``` @@ -282,8 +307,8 @@ Literal ::= [‘-’] integerLiteral ```ebnf integerLiteral ::= (decimalNumeral | hexNumeral) [‘L’ | ‘l’] -decimalNumeral ::= digit {digit} -hexNumeral ::= ‘0’ (‘x’ | ‘X’) hexDigit {hexDigit} +decimalNumeral ::= ‘0’ | digit [{digit | ‘_’} digit] +hexNumeral ::= ‘0’ (‘x’ | ‘X’) hexDigit [{hexDigit | ‘_’} hexDigit] ``` Values of type `Int` are all integer numbers between $-2\^{31}$ and $2\^{31}-1$, inclusive. @@ -312,12 +337,11 @@ The digits of a numeric literal may be separated by arbitrarily many underscores ### Floating Point Literals ```ebnf -floatingPointLiteral ::= digit {digit} ‘.’ digit {digit} [exponentPart] [floatType] - | ‘.’ digit {digit} [exponentPart] [floatType] - | digit {digit} exponentPart [floatType] - | digit {digit} [exponentPart] floatType -exponentPart ::= (‘E’ | ‘e’) [‘+’ | ‘-’] digit {digit} -floatType ::= ‘F’ | ‘f’ | ‘D’ | ‘d’ +floatingPointLiteral + ::= [decimalNumeral] ‘.’ digit [{digit | ‘_’} digit] [exponentPart] [floatType] + | decimalNumeral exponentPart [floatType] + | decimalNumeral floatType +exponentPart ::= (‘E’ | ‘e’) [‘+’ | ‘-’] digit [{digit | ‘_’} digit] ``` Floating point literals are of type `Float` when followed by a floating point type suffix `F` or `f`, and are of type `Double` otherwise. @@ -448,7 +472,7 @@ Inside an interpolated string none of the usual escape characters are interprete Note that the sequence `\"` does not close a normal string literal (enclosed in single quotes). There are three forms of dollar sign escape. -The most general form encloses an expression in `${` and `}`, i.e. `${expr}`. +The most general form encloses an expression in `${` and `}`, i.e. `${expr}`. The expression enclosed in the braces that follow the leading `$` character is of syntactical category BlockExpr. Hence, it can contain multiple statements, and newlines are significant. Single ‘$’-signs are not permitted in isolation in an interpolated string. diff --git a/docs/_spec/03-types.md b/docs/_spec/03-types.md index a1ad1ddffa57..bbaac5de03a0 100644 --- a/docs/_spec/03-types.md +++ b/docs/_spec/03-types.md @@ -8,9 +8,12 @@ chapter: 3 ```ebnf Type ::= FunctionArgTypes ‘=>’ Type + | TypeLambdaParams ‘=>>’ Type | InfixType FunctionArgTypes ::= InfixType | ‘(’ [ ParamType {‘,’ ParamType } ] ‘)’ + TypeLambdaParams ::= ‘[’ TypeLambdaParam {‘,’ TypeLambdaParam} ‘]’ + TypeLambdaParam ::= {Annotation} (id | ‘_’) [TypeParamClause] [‘>:’ Type] [‘<:’ Type] InfixType ::= CompoundType {id [nl] CompoundType} CompoundType ::= AnnotType {‘with’ AnnotType} [Refinement] | Refinement @@ -26,15 +29,16 @@ chapter: 3 ``` We distinguish between proper types and type constructors, which take type parameters and yield types. +All types have a _kind_, either the kind of proper types or a _higher kind_. A subset of proper types called _value types_ represents sets of (first-class) values. -Value types are either _concrete_ or _abstract_. +Types are either _concrete_ or _abstract_. Every concrete value type can be represented as a _class type_, i.e. a [type designator](#type-designators) that refers to a [class or a trait](05-classes-and-objects.html#class-definitions) [^1], or as a [compound type](#compound-types) representing an intersection of types, possibly with a [refinement](#compound-types) that further constrains the types of its members. -Abstract value types are introduced by [type parameters](04-basic-declarations-and-definitions.html#type-parameters) and [abstract type bindings](04-basic-declarations-and-definitions.html#type-declarations-and-type-aliases). +Abstract types are introduced by [type parameters](04-basic-declarations-and-definitions.html#type-parameters) and [abstract type bindings](04-basic-declarations-and-definitions.html#type-declarations-and-type-aliases). Parentheses in types can be used for grouping. [^1]: We assume that objects and packages also implicitly @@ -45,10 +49,14 @@ Non-value types capture properties of identifiers that [are not values](#non-val For example, a [type constructor](#type-constructors) does not directly specify a type of values. However, when a type constructor is applied to the correct type arguments, it yields a proper type, which may be a value type. -Non-value types are expressed indirectly in Scala. +Non-value types are expressed indirectly in Scala. E.g., a method type is described by writing down a method signature, which in itself is not a real type, although it gives rise to a corresponding [method type](#method-types). Type constructors are another example, as one can write `type Swap[m[_, _], a,b] = m[b, a]`, but there is no syntax to write the corresponding anonymous type function directly. +`AnyKind` is the super type of all types in the Scala type system. +It has all possible kinds to encode [kind polymorphism](#kind-polymorphism). +As such, it is neither a value type nor a type constructor. + ## Paths ```ebnf @@ -130,7 +138,7 @@ SimpleType ::= StableId ``` A _type designator_ refers to a named value type. -It can be simple or qualified. +It can be simple or qualified. All such type designators are shorthands for type projections. Specifically, the unqualified type name ´t´ where ´t´ is bound in some class, object, or package ´C´ is taken as a shorthand for @@ -306,14 +314,14 @@ RefineStat ::= Dcl | ``` -A _compound type_ ´T_1´ `with` ... `with` ´T_n \\{ R \\}´ represents objects with members as given in the component types ´T_1, ..., T_n´ and the refinement ´\\{ R \\}´. +A _compound type_ ´T_1´ `with` ... `with` ´T_n \\{ R \\}´ represents objects with members as given in the component types ´T_1, ..., T_n´ and the refinement ´\\{ R \\}´. A refinement ´\\{ R \\}´ contains declarations and type definitions. If a declaration or definition overrides a declaration or definition in one of the component types ´T_1, ..., T_n´, the usual rules for [overriding](05-classes-and-objects.html#overriding) apply; otherwise the declaration or definition 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. -Within a method declaration in a structural refinement, the type of any value parameter may only refer to type parameters or abstract types that are contained inside the refinement. -That is, it must refer either to a type parameter of the method itself, or to a type definition within the refinement. +Within a method declaration in a structural refinement, the type of any value parameter may only refer to type parameters or abstract types that are contained inside the refinement. +That is, it must refer either to a type parameter of the method itself, or to a type definition within the refinement. This restriction does not apply to the method's result type. If no refinement is given, the empty refinement is implicitly added, i.e. ´T_1´ `with` ... `with` ´T_n´ is a shorthand for ´T_1´ `with` ... `with` ´T_n \\{\\}´. @@ -359,12 +367,64 @@ An _infix type_ ´T_1´ `op` ´T_2´ consists of an infix operator `op` which ge The type is equivalent to the type application `op`´[T_1, T_2]´. The infix operator `op` may be an arbitrary identifier. -All type infix operators have the same precedence; parentheses have to be used for grouping. -The [associativity](06-expressions.html#prefix,-infix,-and-postfix-operations) of a type operator is determined as for term operators: type operators ending in a colon ‘:’ are right-associative; all other operators are left-associative. +Type operators follow the same [precedence and associativity as term operators](06-expressions.html#prefix-infix-and-postfix-operations). +For example, `A + B * C` parses as `A + (B * C)` and `A | B & C` parses as `A | (B & C)`. +Type operators ending in a colon ‘:’ are right-associative; all other operators are left-associative. In a sequence of consecutive type infix operations ´t_0 \, \mathit{op} \, t_1 \, \mathit{op_2} \, ... \, \mathit{op_n} \, t_n´, all operators ´\mathit{op}\_1, ..., \mathit{op}\_n´ must have the same associativity. If they are all left-associative, the sequence is interpreted as ´(... (t_0 \mathit{op_1} t_1) \mathit{op_2} ...) \mathit{op_n} t_n´, otherwise it is interpreted as ´t_0 \mathit{op_1} (t_1 \mathit{op_2} ( ... \mathit{op_n} t_n) ...)´. +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. + +### Union and Intersection Types + +Syntactically, the types `S | T` and `S & T` are infix types, where the infix operators are `|` and `&`, respectively (see above). + +However, in this specification, ´S | T´ and ´S & T´ refer to the underlying core concepts of *union and intersection types*, respectively. + +- The type ´S | T´ represents the set of values that are represented by *either* ´S´ or ´T´. +- The type ´S & T´ represents the set of values that are represented by *both* ´S´ and ´T´. + +From the [conformance rules](#conformance) rules on union and intersection types, we can show that ´&´ and ´|´ are *commutative* and *associative*. +Moreover, `&` is distributive over `|`. +For any type ´A´, ´B´ and ´C´, all of the following relationships hold: + +- ´A & B \equiv B & A´, +- ´A | B \equiv B | A´, +- ´(A & B) & C \equiv A & (B & C)´, +- ´(A | B) | C \equiv A | (B | C)´, and +- ´A & (B | C) \equiv (A & B) | (A & C)´. + +If ´C´ is a type constructor, then ´C[A] & C[B]´ can be simplified using the following three rules: + +- If ´C´ is covariant, ´C[A] & C[B] \equiv C[A & B]´ +- If ´C´ is contravariant, ´C[A] & C[B] \equiv C[A | B]´ +- If ´C´ is invariant, emit a compile error + +From the above rules, we can derive the following conformance relationships: + +- When ´C´ is covariant, ´C[A & B] <: C[A] & C[B]´. +- When ´C´ is contravariant, ´C[A | B] <: C[A] & C[B]´. + +#### Join of a union type + +In some situations, a union type might need to be widened to a non-union type. +For this purpose, we define the _join_ of a union type ´T_1 | ... | T_n´ as the smallest intersection type of base class instances of ´T_1, ..., T_n´. +Note that union types might still appear as type arguments in the resulting type, this guarantees that the join is always finite. + +For example, given + +```scala +trait C[+T] +trait D +trait E +class A extends C[A] with D +class B extends C[B] with D with E +``` + +The join of ´A | B´ is ´C[A | B] & D´ + ### Function Types ```ebnf @@ -382,7 +442,7 @@ Function types associate to the right, e.g. ´S \Rightarrow T \Rightarrow R´ is 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 shorthands for class types that define an `apply` method. -Specifically, the ´n´-ary function type ´(T_1, ..., T_n) \Rightarrow R´ is a shorthand for the class type `Function´_n´[´T_1´, ..., ´T_n´, ´R´]`. +Specifically, the ´n´-ary function type ´(T_1, ..., T_n) \Rightarrow R´ is a shorthand for the class type `Function´_n´[´T_1´, ..., ´T_n´, ´R´]`. In particular ´() \Rightarrow R´ is a shorthand for class type `Function´_0´[´R´]`. Such class types behave as if they were instances of the following trait: @@ -396,8 +456,7 @@ Their exact supertype and implementation can be consulted in the [function class ## Non-Value Types -The types explained in the following do not denote sets of values, nor do they appear explicitly in programs. -They are introduced in this report as the internal types of defined identifiers. +The types explained in the following do not denote sets of values. ### Method Types @@ -454,20 +513,30 @@ union : [A >: Nothing <: Comparable[A]] (x: Set[A], xs: Set[A]) Set[A] ### Type Constructors -A _type constructor_ is represented internally much like a polymorphic method type. -`[´\pm´ ´a_1´ >: ´L_1´ <: ´U_1, ..., \pm a_n´ >: ´L_n´ <: ´U_n´] ´T´` represents a type that is expected by a [type constructor parameter](04-basic-declarations-and-definitions.html#type-parameters) or an [abstract type constructor binding](04-basic-declarations-and-definitions.html#type-declarations-and-type-aliases) with the corresponding type parameter clause. +``` +Type ::= ... | TypeLambdaParams ‘=>>’ Type +TypeParamClause ::= ‘[’ TypeParam {‘,’ TypeParam} ‘]’ +TypeLambdaParams ::= ‘[’ TypeLambdaParam {‘,’ TypeLambdaParam} ‘]’ +TypeLambdaParam ::= {Annotation} (id | ‘_’) [TypeParamClause] [‘>:’ Type] [‘<:’ Type] +``` -###### Example + -Consider this fragment of the `Iterable[+X]` class: +A _type constructor_ is either: +- a _type lambda_, of the form `[´\mathit{tps}\,´] =>> ´T´` where `[´\mathit{tps}\,´]` is a type parameter clause `[´a_1´ >: ´L_1´ <: ´U_1, ..., a_n´ >: ´L_n´ <: ´U_n´]` for some ´n \gt 0´ and ´T´ is either a value type +or another type lambda. +- a reference to a [desugared type declaration](04-basic-declarations-and-definitions.html#type-declarations-and-type-aliases) upper-bounded by a type lambda. +- a reference to a [polymorphic class](05-classes-and-objects.html##class-definitions). -```scala -trait Iterable[+X] { - def flatMap[newType[+X] <: Iterable[X], S](f: X => newType[S]): newType[S] -} -``` +Each type parameter ´a_i´ of a type lambda has a variance ´v_i´ which cannot be written down by the user but is inferred from the body of the type lambda to maximize the number of types that conform to the type lambda. + + +#### Inferred type parameter clause -Conceptually, the type constructor `Iterable` is a name for the anonymous type `[+X] Iterable[X]`, which may be passed to the `newType` type constructor parameter in `flatMap`. +To each type constructor corresponds an _inferred type parameter clause_ which is computed as follow: +- For a type lambda, its type parameter clause (including variance annotations). +- For a type declaration upper-bounded by a type lambda ´T´, the inferred clause of ´T´. +- For a polymorphic class, its type parameter clause. +## Kind Polymorphism + +Type parameters are normally partitioned into _kinds_, indicated by the top type of which it is a subtype. +Proper types are the types of values and are subtypes of `Any`. +Higher-kinded types are type constructors such as `List` or `Map`. +Covariant single argument type constructors such as `List` are subtypes of `[+X] =>> Any`. +The `Map` type constructor is a subtype of `[X, +Y] =>> Any`. + +A type can be used only as prescribed by its kind. +Subtypes of `Any` cannot be applied to type arguments whereas subtypes of `[X] =>> Any` _must_ be applied to a type argument, unless they are passed to type parameters of the same kind. + +A type parameter whose upper bound is [`scala.AnyKind`](https://scala-lang.org/api/3.x/scala/AnyKind.html) can have any kind and is called an _any-kinded type_. + +```scala +def f[T <: AnyKind] = ... +``` + +The actual type arguments of `f` can then be types of arbitrary kinds. +So the following are all legal: + +```scala +f[Int] +f[List] +f[Map] +f[[X] =>> String] +``` + +Since the actual kind of an any-kinded type is unknown, its usage is heavily restricted. +An any-kinded type can neither be the type of a value, nor be instantiated with type parameters. +The only thing one can do with an any-kinded type is to pass it to another any-kinded type argument. + +`AnyKind` plays a special role in Scala's subtype system. +It is a supertype of all other types, no matter what their kind is. +It is also assumed to be kind-compatible with all other types. +Furthermore, `AnyKind` is itself an any-kinded type, so it cannot be the type of values and it cannot be instantiated. + ## Base Types and Member Definitions Types of class members depend on the way the members are referenced. @@ -548,6 +653,8 @@ If ´T´ is a possibly parameterized class type, where ´T´'s class is defined 1. The _member bindings_ of a type ´T´ are 1. all bindings ´d´ such that there exists a type instance of some class ´C´ among the base types of ´T´ and there exists a definition or declaration ´d'´ in ´C´ such that ´d´ results from ´d'´ by replacing every type ´T'´ in ´d'´ by ´T'´ in ´C´ seen from ´T´, and 2. all bindings of the type's [refinement](#compound-types), if it has one. +2. The member bindinds of ´S & T´ are all the binds of ´S´ *and* all the bindins of ´T´. +3. The member bindings of ´S | T´ are the member bindings of its [join](#join-of-a-union-type). The _definition_ of a type projection `S#T` is the member binding ´d_T´ of the type `T` in `S`. In that case, we also say that `S#T` _is defined by_ ´d_T´. @@ -565,6 +672,8 @@ We define the following relations between types. ### Equivalence +´\color{red}{\text{TODO SCALA3: Redefine equivalence as mutual conformance?}}´ + Equivalence ´(\equiv)´ between types is the smallest congruence [^congruence] such that the following holds: - If ´t´ is defined by a type alias `type ´t´ = ´T´`, then ´t´ is equivalent to ´T´. @@ -588,8 +697,9 @@ Equivalence ´(\equiv)´ between types is the smallest congruence [^congruence] The conformance relation ´(<:)´ is the smallest transitive relation that satisfies the following conditions. - Conformance includes equivalence. If ´T \equiv U´ then ´T <: U´. -- For every value type `T`, `scala.Nothing <: ´T´ <: scala.Any`. -- For every type constructor ´T´ (with any number of type parameters), `scala.Nothing <: ´T´ <: scala.Any`. +- For every type `´T´` (of any kind), `scala.Nothing <: ´T´ <: scala.AnyKind`. +- For every value type `´T´`, `´T´ <: scala.Any`. +- For every type constructor `´T´` with type parameters `[´U_1´, ..., ´U_n´]`, `[´U_1´, ..., ´U_n´] =>> scala.Nothing <: ´T´ <: [´U_1´, ..., ´U_n´] =>> scala.Any`. - For every value type ´T´, `scala.Null <: ´T´` unless `´T´ <: scala.AnyVal`. - A type variable or abstract type ´t´ conforms to its upper bound and its lower bound conforms to ´t´. - A class type or parameterized type conforms to any of its base-types. @@ -605,10 +715,14 @@ The conformance relation ´(<:)´ is the smallest transitive relation that satis 1. If ´U_i´ is a wildcard type argument of the form ´\\_ >: L_2 <: U_2´, then ´L_2 <: T_i´ and ´T_i <: U_2´. - A compound type `´T_1´ with ... with ´T_n´ {´R\,´}` conforms to each of its component types ´T_i´. - If ´T <: U_i´ for ´i \in \{ 1, ..., n \}´ and for every binding ´d´ of a type or value ´x´ in ´R´ there exists a member binding of ´x´ in ´T´ which subsumes ´d´, then ´T´ conforms to the compound type `´U_1´ with ... with ´U_n´ {´R\,´}`. +- If ´T <: U´, then ´T <: U | W´ and ´T <: W | U´. +- If ´T <: W´ and ´U <: W´, then ´T | U <: W´. +- If ´T <: U´ and ´T <: W´, then ´T <: U & W´. +- If ´T <: W´, then ´T & U <: W´ and ´U & T <: W´. - If ´T_i \equiv T_i'´ for ´i \in \{ 1, ..., n\}´ and ´U´ conforms to ´U'´ then the method type ´(p_1:T_1, ..., p_n:T_n) U´ conforms to ´(p_1':T_1', ..., p_n':T_n') U'´. - The polymorphic type ´[a_1 >: L_1 <: U_1, ..., a_n >: L_n <: U_n] T´ conforms to the polymorphic type ´[a_1 >: L_1' <: U_1', ..., a_n >: L_n' <: U_n'] T'´ if, assuming ´L_1' <: a_1 <: U_1', ..., L_n' <: a_n <: U_n'´ one has ´T <: T'´ and ´L_i <: L_i'´ and ´U_i' <: U_i´ for ´i \in \{ 1, ..., n \}´. - Type constructors ´T´ and ´T'´ follow a similar discipline. -We characterize ´T´ and ´T'´ by their type parameter clauses ´[a_1, ..., a_n]´ and ´[a_1', ..., a_n']´, where an ´a_i´ or ´a_i'´ may include a variance annotation, a higher-order type parameter clause, and bounds. +We characterize ´T´ and ´T'´ by their [inferred type parameter clauses](#inferred-type-parameter-clause) ´[a_1, ..., a_n]´ and ´[a_1', ..., a_n']´. Then, ´T´ conforms to ´T'´ if any list ´[t_1, ..., t_n]´ -- with declared variances, bounds and higher-order type parameter clauses -- of valid type arguments for ´T'´ is also a valid list of type arguments for ´T´ and ´T[t_1, ..., t_n] <: T'[t_1, ..., t_n]´. Note that this entails that: - The bounds on ´a_i´ must be weaker than the corresponding bounds declared for ´a'_i´. @@ -625,28 +739,15 @@ A declaration or definition in some compound type of class type ´C´ _subsumes_ - A type declaration `type ´t´[´T_1´, ..., ´T_n´] >: ´L´ <: ´U´` subsumes a type declaration `type ´t´[´T_1´, ..., ´T_n´] >: ´L'´ <: ´U'´` if ´L' <: L´ and ´U <: U'´. - A type or class definition that binds a type name ´t´ subsumes an abstract type declaration `type t[´T_1´, ..., ´T_n´] >: L <: U` if ´L <: t <: U´. - #### Least upper bounds and greatest lower bounds + The ´(<:)´ relation forms pre-order between types, i.e. it is transitive and reflexive. This allows us to define _least upper bounds_ and _greatest lower bounds_ of a set of types in terms of that order. -The least upper bound or greatest lower bound of a set of types does not always exist. -For instance, consider the class definitions: - -```scala -class A[+T] {} -class B extends A[B] -class C extends A[C] -``` -Then the types `A[Any], A[A[Any]], A[A[A[Any]]], ...` form a descending sequence of upper bounds for `B` and `C`. -The least upper bound would be the infinite limit of that sequence, which does not exist as a Scala type. -Since cases like this are in general impossible to detect, a Scala compiler is free to reject a term which has a type specified as a least upper or greatest lower bound, and that bound would be more complex than some compiler-set limit [^4]. +- the _least upper bound_ of `A` and `B` is the smallest type `L` such that `A` <: `L` and `B` <: `L`. +- the _greatest lower bound_ of `A` and `B` is the largest type `G` such that `G` <: `A` and `G` <: `B`. -The least upper bound or greatest lower bound might also not be unique. -For instance `A with B` and `B with A` are both greatest lower bounds of `A` and `B`. -If there are several least upper bounds or greatest lower bounds, the Scala compiler is free to pick any one of them. - -[^4]: The current Scala compiler limits the nesting level of parameterization in such bounds to be at most two deeper than the maximum nesting level of the operand types +By construction, for all types `A` and `B`, the least upper bound of `A` and `B` is `A | B`, and their greatest lower bound is `A & B`. ### Weak Conformance @@ -716,6 +817,7 @@ _Type erasure_ is a mapping from (possibly generic) types to non-generic types. We write ´|T|´ for the erasure of type ´T´. The erasure mapping is defined as follows. +- The erasure of `scala.AnyKind` is `Object`. - The erasure of an alias type is the erasure of its right-hand side. - The erasure of an abstract type is the erasure of its upper bound. - The erasure of the parameterized type `scala.Array´[T_1]´` is `scala.Array´[|T_1|]´`. @@ -723,7 +825,29 @@ The erasure mapping is defined as follows. - The erasure of a singleton type `´p´.type` is the erasure of the type of ´p´. - The erasure of a type projection `´T´#´x´` is `|´T´|#´x´`. - The erasure of a compound type `´T_1´ with ... with ´T_n´ {´R\,´}` is the erasure of the intersection dominator of ´T_1, ..., T_n´. +- The erasure of a union type ´S | T´ is the _erased least upper bound_ (_elub_) of the erasures of ´S´ and ´T´. +- The erasure of an intersection type ´S & T´ is the _eglb_ (erased greatest lower bound) of the erasures of ´S´ and ´T´. + +The erased LUB is computed as follows: + +- if both argument are arrays of objects, an array of the erased LUB of the element types +- if both arguments are arrays of same primitives, an array of this primitive +- if one argument is array of primitives and the other is array of objects, [`Object`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html) +- if one argument is an array, [`Object`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html) +- otherwise a common superclass or trait S of the argument classes, with the following two properties: + - S is minimal: no other common superclass or trait derives from S, and + - S is last: in the linearization of the first argument type ´|A|´ there are no minimal common superclasses or traits that come after S. + The reason to pick last is that we prefer classes over traits that way, which leads to more predictable bytecode and (?) faster dynamic dispatch. -The _intersection dominator_ of a list of types ´T_1, ..., T_n´ is computed as follows. -Let ´T_{i_1}, ..., T_{i_m}´ be the subsequence of types ´T_i´ which are not supertypes of some other type ´T_j´. -If this subsequence contains a type designator ´T_c´ that refers to a class which is not a trait, the intersection dominator is ´T_c´. Otherwise, the intersection dominator is the first element of the subsequence, ´T_{i_1}´. +The rules for ´eglb(A, B)´ are given below in pseudocode: + +``` +eglb(scala.Array[A], JArray[B]) = scala.Array[eglb(A, B)] +eglb(scala.Array[T], _) = scala.Array[T] +eglb(_, scala.Array[T]) = scala.Array[T] +eglb(A, B) = A if A extends B +eglb(A, B) = B if B extends A +eglb(A, _) = A if A is not a trait +eglb(_, B) = B if B is not a trait +eglb(A, _) = A // use first +``` diff --git a/docs/_spec/04-basic-declarations-and-definitions.md b/docs/_spec/04-basic-declarations-and-definitions.md index 1d50fd649efd..5c45cc5c7819 100644 --- a/docs/_spec/04-basic-declarations-and-definitions.md +++ b/docs/_spec/04-basic-declarations-and-definitions.md @@ -79,7 +79,7 @@ final val x = e ``` where `e` is a [constant expression](06-expressions.html#constant-expressions). -The `final` modifier must be present and no type annotation may be given. +The `final` modifier must be present and no type annotation may be given. References to the constant value `x` are themselves treated as constant expressions; in the generated code they are replaced by the definition's right-hand side `e`. Value definitions can alternatively have a [pattern](08-pattern-matching.html#patterns) as left-hand side. @@ -226,6 +226,54 @@ Def ::= ‘type’ {nl} TypeDef TypeDef ::= id [TypeParamClause] ‘=’ Type ``` +### 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. + +#### Abstract Type +An abstract type +```scala +type ´t´[´\mathit{tps}\,´] >: ´L´ <: ´U´ +``` +is desugared into an unparameterized abstract type as follow: +- If `L` conforms to `Nothing`, then, + + ```scala +type ´t´ >: Nothing + <: [´\mathit{tps'}\,´] =>> ´U´ + ``` +- otherwise, + + ```scala +type ´t´ >: [´\mathit{tps'}\,´] =>> ´L´ + <: [´\mathit{tps'}\,´] =>> ´U´ + ``` + +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, +```scala +[F[X] <: Coll[X]] +``` +is treated as a shorthand for +```scala +[F >: Nothing <: [X] =>> Coll[X]] +``` + +#### Type Alias +A parameterized type alias +```scala +type ´t´[´\mathit{tps}\,´] = ´T´ +``` +is desugared into an unparameterized type alias +```scala +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.}}´ + 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. @@ -311,7 +359,7 @@ TypeParam ::= (id | ‘_’) [TypeParamClause] [‘>:’ Type] [‘<:’ Type parameters appear in type definitions, class definitions, and method definitions. In this section we consider only type parameter definitions with lower bounds `>: ´L´` and upper bounds `<: ´U´` whereas a discussion of context bounds `: ´U´` and view bounds `<% ´U´` is deferred to [here](07-implicits.html#context-bounds-and-view-bounds). -The most general form of a proper type parameter is +The most general form of a proper type parameter is `´@a_1 ... @a_n´ ´\pm´ ´t´ >: ´L´ <: ´U´`. Here, ´L´, and ´U´ are lower and upper bounds that constrain possible type arguments for the parameter. It is a compile-time error if ´L´ does not conform to ´U´. diff --git a/docs/_spec/05-classes-and-objects.md b/docs/_spec/05-classes-and-objects.md index b73a4aa56071..5de7048ba00e 100644 --- a/docs/_spec/05-classes-and-objects.md +++ b/docs/_spec/05-classes-and-objects.md @@ -186,7 +186,7 @@ A member definition ´M´ _matches_ a member definition ´M'´, if ´M´ and ´M 1. Neither ´M´ nor ´M'´ is a method definition. 2. ´M´ and ´M'´ define both monomorphic methods with equivalent argument types. -3. ´M´ defines a parameterless method and ´M'´ defines a method with an empty parameter list `()` or _vice versa_. +3. ´M´ is defined in Java and defines a method with an empty parameter list `()` and ´M'´ defines a parameterless method. 4. ´M´ and ´M'´ define both polymorphic methods with equal number of argument types ´\overline T´, ´\overline T'´ and equal numbers of type parameters ´\overline t´, ´\overline t'´, say, and ´\overline T' = [\overline t'/\overline t]\overline T´. diff --git a/docs/_spec/A1-deprecated.md b/docs/_spec/A1-deprecated.md index e2ebc8af1d35..649c2d7d92e6 100644 --- a/docs/_spec/A1-deprecated.md +++ b/docs/_spec/A1-deprecated.md @@ -18,4 +18,4 @@ scalac Test.scala | For now, you can also `import language.deprecated.symbolLiterals` to accept | the idiom, but this possibility might no longer be available in the future. 1 error found -``` \ No newline at end of file +``` diff --git a/docs/_spec/A2-scala-2-compatibility.md b/docs/_spec/A2-scala-2-compatibility.md index 3621887581a6..30ac1ac32fc2 100644 --- a/docs/_spec/A2-scala-2-compatibility.md +++ b/docs/_spec/A2-scala-2-compatibility.md @@ -32,4 +32,9 @@ def f(): Unit = { ... } Scala 3 accepts the old syntax under the `-source:3.0-migration` option. If the `-migration` option is set, it can even rewrite old syntax to new. The [Scalafix](https://scalacenter.github.io/scalafix/) tool also -can rewrite procedure syntax to make it Scala 3 compatible. \ No newline at end of file +can rewrite procedure syntax to make it Scala 3 compatible. + +## Compound Types (`with`) + +Intersection types `A & B` replace compound types `A with B` in Scala 2. +For the moment, the syntax `A with B` is still allowed and interpreted as `A & B`, but its usage as a type (as opposed to in a `new` or `extends` clause) will be deprecated and removed in the future. diff --git a/docs/_spec/A3-to-be-deprecated.md b/docs/_spec/A3-to-be-deprecated.md index adc37111520c..98f758dee2d4 100644 --- a/docs/_spec/A3-to-be-deprecated.md +++ b/docs/_spec/A3-to-be-deprecated.md @@ -1,4 +1,4 @@ This is a simple list of feature that are not deprecated yet, but will be in the future. They should emit warnings or errors only when using the `-source:future` compiler flag. -- [private[this] and protected[this]](../_docs/reference/dropped-features/this-qualifier.md) \ No newline at end of file +- [private[this] and protected[this]](../_docs/reference/dropped-features/this-qualifier.md) diff --git a/docs/_spec/TODOreference/dropped-features/auto-apply.md b/docs/_spec/APPLIEDreference/dropped-features/auto-apply.md similarity index 98% rename from docs/_spec/TODOreference/dropped-features/auto-apply.md rename to docs/_spec/APPLIEDreference/dropped-features/auto-apply.md index eadfe2f429ea..b9aedb9f046b 100644 --- a/docs/_spec/TODOreference/dropped-features/auto-apply.md +++ b/docs/_spec/APPLIEDreference/dropped-features/auto-apply.md @@ -16,8 +16,8 @@ In Scala 3, this idiom is an error. ```scala next -^ -missing arguments for method next +^^^^ +method next must be called with () argument ``` In Scala 3, the application syntax has to follow exactly the parameter diff --git a/docs/_spec/TODOreference/new-types/intersection-types.md b/docs/_spec/APPLIEDreference/new-types/intersection-types.md similarity index 97% rename from docs/_spec/TODOreference/new-types/intersection-types.md rename to docs/_spec/APPLIEDreference/new-types/intersection-types.md index a4eedeb000f6..4720649e16a9 100644 --- a/docs/_spec/TODOreference/new-types/intersection-types.md +++ b/docs/_spec/APPLIEDreference/new-types/intersection-types.md @@ -63,6 +63,3 @@ to give at that point a definition of a `children` method with the required type class C extends A, B: def children: List[A & B] = ??? ``` - - -[More details](./intersection-types-spec.md) diff --git a/docs/_spec/TODOreference/new-types/type-lambdas.md b/docs/_spec/APPLIEDreference/new-types/type-lambdas.md similarity index 92% rename from docs/_spec/TODOreference/new-types/type-lambdas.md rename to docs/_spec/APPLIEDreference/new-types/type-lambdas.md index ba88e28f5d56..4de3b260c0a2 100644 --- a/docs/_spec/TODOreference/new-types/type-lambdas.md +++ b/docs/_spec/APPLIEDreference/new-types/type-lambdas.md @@ -13,5 +13,3 @@ a type definition. For instance, the type above defines a binary type constructor, which maps arguments `X` and `Y` to `Map[Y, X]`. Type parameters of type lambdas can have bounds, but they cannot carry `+` or `-` variance annotations. - -[More details](./type-lambdas-spec.md) diff --git a/docs/_spec/APPLIEDreference/new-types/union-types.md b/docs/_spec/APPLIEDreference/new-types/union-types.md new file mode 100644 index 000000000000..152505d7fc8d --- /dev/null +++ b/docs/_spec/APPLIEDreference/new-types/union-types.md @@ -0,0 +1,77 @@ +--- +layout: doc-page +title: "Union Types" +nightlyOf: https://docs.scala-lang.org/scala3/reference/new-types/union-types.html +--- + +A union type `A | B` has as values all values of type `A` and also all values of type `B`. + + +```scala +case class UserName(name: String) +case class Password(hash: Hash) + +def help(id: UserName | Password) = + val user = id match + case UserName(name) => lookupName(name) + case Password(hash) => lookupPassword(hash) + ... +``` + +Union types are duals of intersection types. `|` is _commutative_: +`A | B` is the same type as `B | A`. + +The compiler will assign a union type to an expression only if such a +type is explicitly given. This can be seen in the following [REPL](https://docs.scala-lang.org/overviews/repl/overview.html) transcript: + +```scala +scala> val password = Password(123) +val password: Password = Password(123) + +scala> val name = UserName("Eve") +val name: UserName = UserName(Eve) + +scala> if true then name else password +val res2: Object = UserName(Eve) + +scala> val either: Password | UserName = if true then name else password +val either: Password | UserName = UserName(Eve) +``` + +The type of `res2` is `Object & Product`, which is a supertype of +`UserName` and `Password`, but not the least supertype `Password | +UserName`. If we want the least supertype, we have to give it +explicitly, as is done for the type of `either`. + +## Type inference + +When inferring the result type of a definition (`val`, `var`, or `def`) and the +type we are about to infer is a union type, then we replace it by its join. +Similarly, when instantiating a type argument, if the corresponding type +parameter is not upper-bounded by a union type and the type we are about to +instantiate is a union type, we replace it by its join. This mirrors the +treatment of singleton types which are also widened to their underlying type +unless explicitly specified. The motivation is the same: inferring types +which are "too precise" can lead to unintuitive typechecking issues later on. + +**Note:** Since this behavior limits the usability of union types, it might +be changed in the future. For example by not widening unions that have been +explicitly written down by the user and not inferred, or by not widening a type +argument when the corresponding type parameter is covariant. + +See [PR #2330](https://github.com/lampepfl/dotty/pull/2330) and +[Issue #4867](https://github.com/lampepfl/dotty/issues/4867) for further discussions. + +### Example + +```scala +import scala.collection.mutable.ListBuffer +val x = ListBuffer(Right("foo"), Left(0)) +val y: ListBuffer[Either[Int, String]] = x +``` + +This code typechecks because the inferred type argument to `ListBuffer` in the +right-hand side of `x` was `Left[Int, Nothing] | Right[Nothing, String]` which +was widened to `Either[Int, String]`. If the compiler hadn't done this widening, +the last line wouldn't typecheck because `ListBuffer` is invariant in its +argument. diff --git a/docs/_spec/TODOreference/other-new-features/kind-polymorphism.md b/docs/_spec/APPLIEDreference/other-new-features/kind-polymorphism.md similarity index 85% rename from docs/_spec/TODOreference/other-new-features/kind-polymorphism.md rename to docs/_spec/APPLIEDreference/other-new-features/kind-polymorphism.md index 8f0172c4c04b..685630b86f73 100644 --- a/docs/_spec/TODOreference/other-new-features/kind-polymorphism.md +++ b/docs/_spec/APPLIEDreference/other-new-features/kind-polymorphism.md @@ -38,10 +38,4 @@ through advanced uses of implicits. (todo: insert good concise example) -Some technical details: [`AnyKind`](https://scala-lang.org/api/3.x/scala/AnyKind.html) is a synthesized class just like `Any`, but without any members. It extends no other class. -It is declared `abstract` and `final`, so it can be neither instantiated nor extended. - `AnyKind` plays a special role in Scala's subtype system: It is a supertype of all other types no matter what their kind is. It is also assumed to be kind-compatible with all other types. Furthermore, `AnyKind` is treated as a higher-kinded type (so it cannot be used as a type of values), but at the same time it has no type parameters (so it cannot be instantiated). - -**Note**: This feature is considered experimental but stable and it can be disabled under compiler flag -(i.e. `-Yno-kind-polymorphism`). diff --git a/docs/_spec/TODOreference/new-types/intersection-types-spec.md b/docs/_spec/TODOreference/new-types/intersection-types-spec.md deleted file mode 100644 index 346c57c004f0..000000000000 --- a/docs/_spec/TODOreference/new-types/intersection-types-spec.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -layout: doc-page -title: "Intersection Types - More Details" -nightlyOf: https://docs.scala-lang.org/scala3/reference/new-types/intersection-types-spec.html ---- - -## Syntax - -Syntactically, the type `S & T` is an infix type, where the infix operator is `&`. -The operator `&` is a normal identifier -with the usual precedence and subject to usual resolving rules. -Unless shadowed by another definition, it resolves to the type `scala.&`, -which acts as a type alias to an internal representation of intersection types. - -``` -Type ::= ...| InfixType -InfixType ::= RefinedType {id [nl] RefinedType} -``` - -## Subtyping Rules - -``` -T <: A T <: B ----------------- - T <: A & B - - A <: T ----------------- - A & B <: T - - B <: T ----------------- - A & B <: T -``` - -From the rules above, we can show that `&` is _commutative_: `A & B <: B & A` for any type `A` and `B`. - -``` - B <: B A <: A ----------- ----------- -A & B <: B A & B <: A ---------------------------- - A & B <: B & A -``` - -In another word, `A & B` is the same type as `B & A`, in the sense that the two types -have the same values and are subtypes of each other. - -If `C` is a type constructor, then `C[A] & C[B]` can be simplified using the following three rules: - -- If `C` is covariant, `C[A] & C[B] ~> C[A & B]` -- If `C` is contravariant, `C[A] & C[B] ~> C[A | B]` -- If `C` is non-variant, emit a compile error - -When `C` is covariant, `C[A & B] <: C[A] & C[B]` can be derived: - -``` - A <: A B <: B - ---------- --------- - A & B <: A A & B <: B ---------------- ----------------- -C[A & B] <: C[A] C[A & B] <: C[B] ------------------------------------------- - C[A & B] <: C[A] & C[B] -``` - -When `C` is contravariant, `C[A | B] <: C[A] & C[B]` can be derived: - -``` - A <: A B <: B - ---------- --------- - A <: A | B B <: A | B -------------------- ---------------- -C[A | B] <: C[A] C[A | B] <: C[B] --------------------------------------------------- - C[A | B] <: C[A] & C[B] -``` - -## Erasure - -The erased type for `S & T` is the erased _glb_ (greatest lower bound) of the -erased type of `S` and `T`. The rules for erasure of intersection types are given -below in pseudocode: - -``` -|S & T| = glb(|S|, |T|) - -glb(JArray(A), JArray(B)) = JArray(glb(A, B)) -glb(JArray(T), _) = JArray(T) -glb(_, JArray(T)) = JArray(T) -glb(A, B) = A if A extends B -glb(A, B) = B if B extends A -glb(A, _) = A if A is not a trait -glb(_, B) = B if B is not a trait -glb(A, _) = A // use first -``` - -In the above, `|T|` means the erased type of `T`, `JArray` refers to -the type of Java Array. - -See also: [`TypeErasure#erasedGlb`](https://github.com/lampepfl/dotty/blob/main/compiler/src/dotty/tools/dotc/core/TypeErasure.scala#L289). - -## Relationship with Compound Type (`with`) - -Intersection types `A & B` replace compound types `A with B` in Scala 2. For the -moment, the syntax `A with B` is still allowed and interpreted as `A & B`, but -its usage as a type (as opposed to in a `new` or `extends` clause) will be -deprecated and removed in the future. diff --git a/docs/_spec/TODOreference/new-types/type-lambdas-spec.md b/docs/_spec/TODOreference/new-types/type-lambdas-spec.md deleted file mode 100644 index 52f88dab4217..000000000000 --- a/docs/_spec/TODOreference/new-types/type-lambdas-spec.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -layout: doc-page -title: "Type Lambdas - More Details" -nightlyOf: https://docs.scala-lang.org/scala3/reference/new-types/type-lambdas-spec.html ---- - -## Syntax - -``` -Type ::= ... | TypeParamClause ‘=>>’ Type -TypeParamClause ::= ‘[’ TypeParam {‘,’ TypeParam} ‘]’ -TypeParam ::= {Annotation} (id [HkTypeParamClause] | ‘_’) TypeBounds -TypeBounds ::= [‘>:’ Type] [‘<:’ Type] -``` - -## Type Checking - -A type lambda such as `[X] =>> F[X]` defines a function from types to types. The parameter(s) may carry bounds. -If a parameter is bounded, as in `[X >: L <: U] =>> F[X]` it is checked that arguments to the parameters conform to the bounds `L` and `U`. -Only the upper bound `U` can be F-bounded, i.e. `X` can appear in it. - -## Subtyping Rules - -Assume two type lambdas -```scala -type TL1 = [X >: L1 <: U1] =>> R1 -type TL2 = [X >: L2 <: U2] =>> R2 -``` -Then `TL1 <: TL2`, if - - - the type interval `L2..U2` is contained in the type interval `L1..U1` (i.e. -`L1 <: L2` and `U2 <: U1`), - - `R1 <: R2` - -Here we have relied on [alpha renaming](https://en.wikipedia.org/wiki/Lambda_calculus#%CE%B1-conversion) to match the two bound types `X`. - -A partially applied type constructor such as `List` is assumed to be equivalent to -its eta expansion. I.e, `List = [X] =>> List[X]`. This allows type constructors to be compared with type lambdas. - -## Relationship with Parameterized Type Definitions - -A parameterized type definition -```scala -type T[X] = R -``` -is regarded as a shorthand for an unparameterized definition with a type lambda as right-hand side: -```scala -type T = [X] =>> R -``` -If the type definition carries `+` or `-` variance annotations, -it is checked that the variance annotations are satisfied by the type lambda. -For instance, -```scala -type F2[A, +B] = A => B -``` -expands to -```scala -type F2 = [A, B] =>> A => B -``` -and at the same time it is checked that the parameter `B` appears covariantly in `A => B`. - -A parameterized abstract type -```scala -type T[X] >: L <: U -``` -is regarded as shorthand for an unparameterized abstract type with type lambdas as bounds. -```scala -type T >: ([X] =>> L) <: ([X] =>> U) -``` -However, if `L` is `Nothing` it is not parameterized, since `Nothing` is treated as a bottom type for all kinds. For instance, -```scala -type T[X] <: X => X -``` -is expanded to -```scala -type T >: Nothing <: ([X] =>> X => X) -``` -instead of -```scala -type T >: ([X] =>> Nothing) <: ([X] =>> X => X) -``` - -The same expansions apply to type parameters. For instance, -```scala -[F[X] <: Coll[X]] -``` -is treated as a shorthand for -```scala -[F >: Nothing <: [X] =>> Coll[X]] -``` -Abstract types and opaque type aliases remember the variances they were created with. So the type -```scala -type F2[-A, +B] -``` -is known to be contravariant in `A` and covariant in `B` and can be instantiated only -with types that satisfy these constraints. Likewise -```scala -opaque type O[X] = List[X] -``` -`O` is known to be invariant (and not covariant, as its right-hand side would suggest). On the other hand, a transparent alias -```scala -type O2[X] = List[X] -``` -would be treated as covariant, `X` is used covariantly on its right-hand side. - -**Note**: The decision to treat `Nothing` as universal bottom type is provisional, and might be changed after further discussion. - -**Note**: Scala 2 and 3 differ in that Scala 2 also treats `Any` as universal top-type. This is not done in Scala 3. See also the discussion on [kind polymorphism](../other-new-features/kind-polymorphism.md) - -## Curried Type Parameters - -The body of a type lambda can again be a type lambda. Example: -```scala -type TL = [X] =>> [Y] =>> (X, Y) -``` -Currently, no special provision is made to infer type arguments to such curried type lambdas. This is left for future work. diff --git a/docs/_spec/TODOreference/new-types/union-types-spec.md b/docs/_spec/TODOreference/new-types/union-types-spec.md deleted file mode 100644 index d250d3f11713..000000000000 --- a/docs/_spec/TODOreference/new-types/union-types-spec.md +++ /dev/null @@ -1,172 +0,0 @@ ---- -layout: doc-page -title: "Union Types - More Details" -nightlyOf: https://docs.scala-lang.org/scala3/reference/new-types/union-types-spec.html ---- - -## Syntax - -Syntactically, unions follow the same rules as intersections, but have a lower precedence, see -[Intersection Types - More Details](./intersection-types-spec.md). - -### Interaction with pattern matching syntax -`|` is also used in pattern matching to separate pattern alternatives and has -lower precedence than `:` as used in typed patterns, this means that: - -```scala -case _: A | B => ... -``` - -is still equivalent to: - -```scala -case (_: A) | B => ... -``` - -and not to: - -```scala -case _: (A | B) => ... -``` - -## Subtyping Rules - -- `A` is always a subtype of `A | B` for all `A`, `B`. -- If `A <: C` and `B <: C` then `A | B <: C` -- Like `&`, `|` is commutative and associative: - - ```scala - A | B =:= B | A - A | (B | C) =:= (A | B) | C - ``` - -- `&` is distributive over `|`: - - ```scala - A & (B | C) =:= A & B | A & C - ``` - -From these rules it follows that the _least upper bound_ (LUB) of a set of types -is the union of these types. This replaces the -[definition of least upper bound in the Scala 2 specification](https://www.scala-lang.org/files/archive/spec/2.13/03-types.html#least-upper-bounds-and-greatest-lower-bounds). - -## Motivation - -The primary reason for introducing union types in Scala is that they allow us to -guarantee that for every set of types, we can always form a finite LUB. This is -both useful in practice (infinite LUBs in Scala 2 were approximated in an ad-hoc -way, resulting in imprecise and sometimes incredibly long types) and in theory -(the type system of Scala 3 is based on the -[DOT calculus](https://infoscience.epfl.ch/record/227176/files/soundness_oopsla16.pdf), -which has union types). - -Additionally, union types are a useful construct when trying to give types to existing -dynamically typed APIs, this is why they're [an integral part of TypeScript](https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types) -and have even been [partially implemented in Scala.js](https://github.com/scala-js/scala-js/blob/master/library/src/main/scala/scala/scalajs/js/Union.scala). - -## Join of a union type - -In some situation described below, a union type might need to be widened to -a non-union type, for this purpose we define the _join_ of a union type `T1 | -... | Tn` as the smallest intersection type of base class instances of -`T1`,...,`Tn`. Note that union types might still appear as type arguments in the -resulting type, this guarantees that the join is always finite. - -### Example - -Given - -```scala -trait C[+T] -trait D -trait E -class A extends C[A] with D -class B extends C[B] with D with E -``` - -The join of `A | B` is `C[A | B] & D` - -## Type inference - -When inferring the result type of a definition (`val`, `var`, or `def`) and the -type we are about to infer is a union type, then we replace it by its join. -Similarly, when instantiating a type argument, if the corresponding type -parameter is not upper-bounded by a union type and the type we are about to -instantiate is a union type, we replace it by its join. This mirrors the -treatment of singleton types which are also widened to their underlying type -unless explicitly specified. The motivation is the same: inferring types -which are "too precise" can lead to unintuitive typechecking issues later on. - -**Note:** Since this behavior limits the usability of union types, it might -be changed in the future. For example by not widening unions that have been -explicitly written down by the user and not inferred, or by not widening a type -argument when the corresponding type parameter is covariant. - -See [PR #2330](https://github.com/lampepfl/dotty/pull/2330) and -[Issue #4867](https://github.com/lampepfl/dotty/issues/4867) for further discussions. - -### Example - -```scala -import scala.collection.mutable.ListBuffer -val x = ListBuffer(Right("foo"), Left(0)) -val y: ListBuffer[Either[Int, String]] = x -``` - -This code typechecks because the inferred type argument to `ListBuffer` in the -right-hand side of `x` was `Left[Int, Nothing] | Right[Nothing, String]` which -was widened to `Either[Int, String]`. If the compiler hadn't done this widening, -the last line wouldn't typecheck because `ListBuffer` is invariant in its -argument. - - -## Members - -The members of a union type are the members of its join. - -### Example - -The following code does not typecheck, because method `hello` is not a member of -`AnyRef` which is the join of `A | B`. - -```scala -trait A { def hello: String } -trait B { def hello: String } - -def test(x: A | B) = x.hello // error: value `hello` is not a member of A | B -``` - -On the other hand, the following would be allowed - -```scala -trait C { def hello: String } -trait A extends C with D -trait B extends C with E - -def test(x: A | B) = x.hello // ok as `hello` is a member of the join of A | B which is C -``` - -## Exhaustivity checking - -If the selector of a pattern match is a union type, the match is considered -exhaustive if all parts of the union are covered. - -## Erasure - -The erased type for `A | B` is the _erased least upper bound_ of the erased -types of `A` and `B`. Quoting from the documentation of `TypeErasure#erasedLub`, -the erased LUB is computed as follows: - -- if both argument are arrays of objects, an array of the erased LUB of the element types -- if both arguments are arrays of same primitives, an array of this primitive -- if one argument is array of primitives and the other is array of objects, - [`Object`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html) -- if one argument is an array, [`Object`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html) -- otherwise a common superclass or trait S of the argument classes, with the - following two properties: - * S is minimal: no other common superclass or trait derives from S - * S is last : in the linearization of the first argument type `|A|` - there are no minimal common superclasses or traits that - come after S. - The reason to pick last is that we prefer classes over traits that way, - which leads to more predictable bytecode and (?) faster dynamic dispatch. diff --git a/docs/_spec/TODOreference/new-types/union-types.md b/docs/_spec/TODOreference/new-types/union-types.md deleted file mode 100644 index ebc4565e36fb..000000000000 --- a/docs/_spec/TODOreference/new-types/union-types.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -layout: doc-page -title: "Union Types" -nightlyOf: https://docs.scala-lang.org/scala3/reference/new-types/union-types.html ---- - -A union type `A | B` has as values all values of type `A` and also all values of type `B`. - - -```scala -case class UserName(name: String) -case class Password(hash: Hash) - -def help(id: UserName | Password) = - val user = id match - case UserName(name) => lookupName(name) - case Password(hash) => lookupPassword(hash) - ... -``` - -Union types are duals of intersection types. `|` is _commutative_: -`A | B` is the same type as `B | A`. - -The compiler will assign a union type to an expression only if such a -type is explicitly given. This can be seen in the following [REPL](https://docs.scala-lang.org/overviews/repl/overview.html) transcript: - -```scala -scala> val password = Password(123) -val password: Password = Password(123) - -scala> val name = UserName("Eve") -val name: UserName = UserName(Eve) - -scala> if true then name else password -val res2: Object = UserName(Eve) - -scala> val either: Password | UserName = if true then name else password -val either: Password | UserName = UserName(Eve) -``` - -The type of `res2` is `Object & Product`, which is a supertype of -`UserName` and `Password`, but not the least supertype `Password | -UserName`. If we want the least supertype, we have to give it -explicitly, as is done for the type of `either`. - -[More details](./union-types-spec.md) diff --git a/docs/_spec/TODOreference/syntax.md b/docs/_spec/TODOreference/syntax.md deleted file mode 100644 index d3526783a5eb..000000000000 --- a/docs/_spec/TODOreference/syntax.md +++ /dev/null @@ -1,472 +0,0 @@ ---- -layout: doc-page -title: "Scala 3 Syntax Summary" -nightlyOf: https://docs.scala-lang.org/scala3/reference/syntax.html ---- - - - -The following description of Scala tokens uses literal characters `‘c’` when -referring to the ASCII fragment `\u0000` – `\u007F`. - -_Unicode escapes_ are used to represent the [Unicode character](https://www.w3.org/International/articles/definitions-characters/) with the given -hexadecimal code: - -``` -UnicodeEscape ::= ‘\’ ‘u’ {‘u’} hexDigit hexDigit hexDigit hexDigit -hexDigit ::= ‘0’ | ... | ‘9’ | ‘A’ | ... | ‘F’ | ‘a’ | ... | ‘f’ -``` - -Informal descriptions are typeset as `“some comment”`. - -## Lexical Syntax - -The lexical syntax of Scala is given by the following grammar in EBNF -form. - -``` -whiteSpace ::= ‘\u0020’ | ‘\u0009’ | ‘\u000D’ | ‘\u000A’ -upper ::= ‘A’ | ... | ‘Z’ | ‘\$’ | ‘_’ “... and Unicode category Lu” -lower ::= ‘a’ | ... | ‘z’ “... and Unicode category Ll” -letter ::= upper | lower “... and Unicode categories Lo, Lt, Nl” -digit ::= ‘0’ | ... | ‘9’ -paren ::= ‘(’ | ‘)’ | ‘[’ | ‘]’ | ‘{’ | ‘}’ -delim ::= ‘`’ | ‘'’ | ‘"’ | ‘.’ | ‘;’ | ‘,’ -opchar ::= ‘!’ | ‘#’ | ‘%’ | ‘&’ | ‘*’ | ‘+’ | ‘-’ | ‘/’ | ‘:’ | - ‘<’ | ‘=’ | ‘>’ | ‘?’ | ‘@’ | ‘\’ | ‘^’ | ‘|’ | ‘~’ - “... and Unicode categories Sm, So” -printableChar ::= “all characters in [\u0020, \u007E] inclusive” -charEscapeSeq ::= ‘\’ (‘b’ | ‘t’ | ‘n’ | ‘f’ | ‘r’ | ‘"’ | ‘'’ | ‘\’) - -op ::= opchar {opchar} -varid ::= lower idrest -alphaid ::= upper idrest - | varid -plainid ::= alphaid - | op -id ::= plainid - | ‘`’ { charNoBackQuoteOrNewline | UnicodeEscape | charEscapeSeq } ‘`’ -idrest ::= {letter | digit} [‘_’ op] -quoteId ::= ‘'’ alphaid -spliceId ::= ‘$’ alphaid ; - -integerLiteral ::= (decimalNumeral | hexNumeral) [‘L’ | ‘l’] -decimalNumeral ::= ‘0’ | nonZeroDigit [{digit | ‘_’} digit] -hexNumeral ::= ‘0’ (‘x’ | ‘X’) hexDigit [{hexDigit | ‘_’} hexDigit] -nonZeroDigit ::= ‘1’ | ... | ‘9’ - -floatingPointLiteral - ::= [decimalNumeral] ‘.’ digit [{digit | ‘_’} digit] [exponentPart] [floatType] - | decimalNumeral exponentPart [floatType] - | decimalNumeral floatType -exponentPart ::= (‘E’ | ‘e’) [‘+’ | ‘-’] digit [{digit | ‘_’} digit] -floatType ::= ‘F’ | ‘f’ | ‘D’ | ‘d’ - -booleanLiteral ::= ‘true’ | ‘false’ - -characterLiteral ::= ‘'’ (printableChar | charEscapeSeq) ‘'’ - -stringLiteral ::= ‘"’ {stringElement} ‘"’ - | ‘"""’ multiLineChars ‘"""’ -stringElement ::= printableChar \ (‘"’ | ‘\’) - | UnicodeEscape - | charEscapeSeq -multiLineChars ::= {[‘"’] [‘"’] char \ ‘"’} {‘"’} -processedStringLiteral - ::= alphaid ‘"’ {[‘\’] processedStringPart | ‘\\’ | ‘\"’} ‘"’ - | alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘$’) | escape} {‘"’} ‘"""’ -processedStringPart - ::= printableChar \ (‘"’ | ‘$’ | ‘\’) | escape -escape ::= ‘$$’ - | ‘$’ letter { letter | digit } - | ‘{’ Block [‘;’ whiteSpace stringFormat whiteSpace] ‘}’ -stringFormat ::= {printableChar \ (‘"’ | ‘}’ | ‘ ’ | ‘\t’ | ‘\n’)} - -symbolLiteral ::= ‘'’ plainid // until 2.13 - -comment ::= ‘/*’ “any sequence of characters; nested comments are allowed” ‘*/’ - | ‘//’ “any sequence of characters up to end of line” - -nl ::= “new line character” -semi ::= ‘;’ | nl {nl} -``` - -## Optional Braces - -The lexical analyzer also inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](./other-new-features/indentation.md). - -In the context-free productions below we use the notation `<<< ts >>>` -to indicate a token sequence `ts` that is either enclosed in a pair of braces `{ ts }` or that constitutes an indented region `indent ts outdent`. Analogously, the -notation `:<<< ts >>>` indicates a token sequence `ts` that is either enclosed in a pair of braces `{ ts }` or that constitutes an indented region `indent ts outdent` that follows -a `colon` token. - -A `colon` token reads as the standard colon "`:`" but is generated instead of it where `colon` is legal according to the context free syntax, but only if the previous token -is an alphanumeric identifier, a backticked identifier, or one of the tokens `this`, `super`, `new`, "`)`", and "`]`". - -``` -colon ::= ':' -- with side conditions explained above - <<< ts >>> ::= ‘{’ ts ‘}’ - | indent ts outdent -:<<< ts >>> ::= [nl] ‘{’ ts ‘}’ - | colon indent ts outdent -``` - -## Keywords - -### Regular keywords - -``` -abstract case catch class def do else -enum export extends false final finally for -given if implicit import lazy match new -null object override package private protected return -sealed super then throw trait true try -type val var while with yield -: = <- => <: >: # -@ =>> ?=> -``` - -### Soft keywords - -``` -as derives end extension infix inline opaque open transparent using | * + - -``` - -See the [separate section on soft keywords](./soft-modifier.md) for additional -details on where a soft keyword is recognized. - -## Context-free Syntax - -The context-free syntax of Scala is given by the following EBNF -grammar: - -### Literals and Paths -``` -SimpleLiteral ::= [‘-’] integerLiteral - | [‘-’] floatingPointLiteral - | booleanLiteral - | characterLiteral - | stringLiteral -Literal ::= SimpleLiteral - | processedStringLiteral - | symbolLiteral - | ‘null’ - -QualId ::= id {‘.’ id} -ids ::= id {‘,’ id} - -SimpleRef ::= id - | [id ‘.’] ‘this’ - | [id ‘.’] ‘super’ [ClassQualifier] ‘.’ id - -ClassQualifier ::= ‘[’ id ‘]’ -``` - -### Types -``` -Type ::= FunType - | HkTypeParamClause ‘=>>’ Type - | FunParamClause ‘=>>’ Type - | MatchType - | InfixType -FunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type - | HKTypeParamClause '=>' Type -FunTypeArgs ::= InfixType - | ‘(’ [ FunArgTypes ] ‘)’ - | FunParamClause -FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’ -TypedFunParam ::= id ‘:’ Type -MatchType ::= InfixType `match` <<< TypeCaseClauses >>> -InfixType ::= RefinedType {id [nl] RefinedType} -RefinedType ::= AnnotType {[nl] Refinement} -AnnotType ::= SimpleType {Annotation} - -SimpleType ::= SimpleLiteral - | ‘?’ TypeBounds - | id - | Singleton ‘.’ id - | Singleton ‘.’ ‘type’ - | ‘(’ Types ‘)’ - | Refinement - | SimpleType1 TypeArgs - | SimpleType1 ‘#’ id -Singleton ::= SimpleRef - | SimpleLiteral - | Singleton ‘.’ id - -FunArgType ::= Type - | ‘=>’ Type -FunArgTypes ::= FunArgType { ‘,’ FunArgType } -ParamType ::= [‘=>’] ParamValueType -ParamValueType ::= Type [‘*’] -TypeArgs ::= ‘[’ Types ‘]’ -Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>> -TypeBounds ::= [‘>:’ Type] [‘<:’ Type] -TypeParamBounds ::= TypeBounds {‘:’ Type} -Types ::= Type {‘,’ Type} -``` - -### Expressions -``` -Expr ::= FunParams (‘=>’ | ‘?=>’) Expr - | HkTypeParamClause ‘=>’ Expr - | Expr1 -BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block - | HkTypeParamClause ‘=>’ Block - | Expr1 -FunParams ::= Bindings - | id - | ‘_’ -Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] ‘else’ Expr] - | [‘inline’] ‘if’ Expr ‘then’ Expr [[semi] ‘else’ Expr] - | ‘while’ ‘(’ Expr ‘)’ {nl} Expr - | ‘while’ Expr ‘do’ Expr - | ‘try’ Expr Catches [‘finally’ Expr] - | ‘try’ Expr [‘finally’ Expr] - | ‘throw’ Expr - | ‘return’ [Expr] - | ForExpr - | [SimpleExpr ‘.’] id ‘=’ Expr - | PrefixOperator SimpleExpr ‘=’ Expr - | SimpleExpr ArgumentExprs ‘=’ Expr - | PostfixExpr [Ascription] - | ‘inline’ InfixExpr MatchClause -Ascription ::= ‘:’ InfixType - | ‘:’ Annotation {Annotation} -Catches ::= ‘catch’ (Expr | ExprCaseClause) -PostfixExpr ::= InfixExpr [id] -- only if language.postfixOperators is enabled -InfixExpr ::= PrefixExpr - | InfixExpr id [nl] InfixExpr - | InfixExpr MatchClause -MatchClause ::= ‘match’ <<< CaseClauses >>> -PrefixExpr ::= [PrefixOperator] SimpleExpr -PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ -- unless backquoted -SimpleExpr ::= SimpleRef - | Literal - | ‘_’ - | BlockExpr - | ExprSplice - | Quoted - | quoteId -- only inside splices - | ‘new’ ConstrApp {‘with’ ConstrApp} [TemplateBody] - | ‘new’ TemplateBody - | ‘(’ ExprsInParens ‘)’ - | SimpleExpr ‘.’ id - | SimpleExpr ‘.’ MatchClause - | SimpleExpr TypeArgs - | SimpleExpr ArgumentExprs -Quoted ::= ‘'’ ‘{’ Block ‘}’ - | ‘'’ ‘[’ Type ‘]’ -ExprSplice ::= spliceId -- if inside quoted block - | ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern - | ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted pattern -ExprsInParens ::= ExprInParens {‘,’ ExprInParens} -ExprInParens ::= PostfixExpr ‘:’ Type - | Expr -ParArgumentExprs ::= ‘(’ [ExprsInParens] ‘)’ - | ‘(’ ‘using’ ExprsInParens ‘)’ - | ‘(’ [ExprsInParens ‘,’] PostfixExpr ‘*’ ‘)’ -ArgumentExprs ::= ParArgumentExprs - | BlockExpr -BlockExpr ::= <<< (CaseClauses | Block) >>> -Block ::= {BlockStat semi} [BlockResult] -BlockStat ::= Import - | {Annotation {nl}} {LocalModifier} Def - | Extension - | Expr1 - | EndMarker - -ForExpr ::= ‘for’ ‘(’ Enumerators0 ‘)’ {nl} [‘do‘ | ‘yield’] Expr - | ‘for’ ‘{’ Enumerators0 ‘}’ {nl} [‘do‘ | ‘yield’] Expr - | ‘for’ Enumerators0 (‘do‘ | ‘yield’) Expr -Enumerators0 ::= {nl} Enumerators [semi] -Enumerators ::= Generator {semi Enumerator | Guard} -Enumerator ::= Generator - | Guard {Guard} - | Pattern1 ‘=’ Expr -Generator ::= [‘case’] Pattern1 ‘<-’ Expr -Guard ::= ‘if’ PostfixExpr - -CaseClauses ::= CaseClause { CaseClause } -CaseClause ::= ‘case’ Pattern [Guard] ‘=>’ Block -ExprCaseClause ::= ‘case’ Pattern [Guard] ‘=>’ Expr -TypeCaseClauses ::= TypeCaseClause { TypeCaseClause } -TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi] - -Pattern ::= Pattern1 { ‘|’ Pattern1 } -Pattern1 ::= Pattern2 [‘:’ RefinedType] -Pattern2 ::= [id ‘@’] InfixPattern [‘*’] -InfixPattern ::= SimplePattern { id [nl] SimplePattern } -SimplePattern ::= PatVar - | Literal - | ‘(’ [Patterns] ‘)’ - | Quoted - | SimplePattern1 [TypeArgs] [ArgumentPatterns] - | ‘given’ RefinedType -SimplePattern1 ::= SimpleRef - | SimplePattern1 ‘.’ id -PatVar ::= varid - | ‘_’ -Patterns ::= Pattern {‘,’ Pattern} -ArgumentPatterns ::= ‘(’ [Patterns] ‘)’ - | ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’ -``` - -### Type and Value Parameters -``` -ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’ -ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] id [HkTypeParamClause] TypeParamBounds - -DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’ -DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds - -TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’ -TypTypeParam ::= {Annotation} id [HkTypeParamClause] TypeBounds - -HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’ -HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypeParamClause] | ‘_’) TypeBounds - -ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’] -ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’ - | [nl] ‘(’ ‘using’ (ClsParams | FunArgTypes) ‘)’ -ClsParams ::= ClsParam {‘,’ ClsParam} -ClsParam ::= {Annotation} [{Modifier} (‘val’ | ‘var’) | ‘inline’] Param -Param ::= id ‘:’ ParamType [‘=’ Expr] - -DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’] -DefParamClause ::= [nl] ‘(’ DefParams ‘)’ | UsingParamClause -UsingParamClause ::= [nl] ‘(’ ‘using’ (DefParams | FunArgTypes) ‘)’ -DefParams ::= DefParam {‘,’ DefParam} -DefParam ::= {Annotation} [‘inline’] Param -``` - -### Bindings and Imports -``` -Bindings ::= ‘(’ [Binding {‘,’ Binding}] ‘)’ -Binding ::= (id | ‘_’) [‘:’ Type] - -Modifier ::= LocalModifier - | AccessModifier - | ‘override’ - | ‘opaque’ -LocalModifier ::= ‘abstract’ - | ‘final’ - | ‘sealed’ - | ‘open’ - | ‘implicit’ - | ‘lazy’ - | ‘inline’ -AccessModifier ::= (‘private’ | ‘protected’) [AccessQualifier] -AccessQualifier ::= ‘[’ id ‘]’ - -Annotation ::= ‘@’ SimpleType1 {ParArgumentExprs} - -Import ::= ‘import’ ImportExpr {‘,’ ImportExpr} -Export ::= ‘export’ ImportExpr {‘,’ ImportExpr} -ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec - | SimpleRef ‘as’ id -ImportSpec ::= NamedSelector - | WildcardSelector - | ‘{’ ImportSelectors) ‘}’ -NamedSelector ::= id [‘as’ (id | ‘_’)] -WildCardSelector ::= ‘*' | ‘given’ [InfixType] -ImportSelectors ::= NamedSelector [‘,’ ImportSelectors] - | WildCardSelector {‘,’ WildCardSelector} - -EndMarker ::= ‘end’ EndMarkerTag -- when followed by EOL -EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ | ‘try’ - | ‘new’ | ‘this’ | ‘given’ | ‘extension’ | ‘val’ -``` - -### Declarations and Definitions -``` -RefineDcl ::= ‘val’ ValDcl - | ‘def’ DefDcl - | ‘type’ {nl} TypeDcl -Dcl ::= RefineDcl - | ‘var’ VarDcl -ValDcl ::= ids ‘:’ Type -VarDcl ::= ids ‘:’ Type -DefDcl ::= DefSig ‘:’ Type -DefSig ::= id [DefTypeParamClause] DefParamClauses -TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type] - -Def ::= ‘val’ PatDef - | ‘var’ PatDef - | ‘def’ DefDef - | ‘type’ {nl} TypeDcl - | TmplDef -PatDef ::= ids [‘:’ Type] ‘=’ Expr - | Pattern2 [‘:’ Type] ‘=’ Expr -DefDef ::= DefSig [‘:’ Type] ‘=’ Expr - | ‘this’ DefParamClause DefParamClauses ‘=’ ConstrExpr - -TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef - | [‘case’] ‘object’ ObjectDef - | ‘enum’ EnumDef - | ‘given’ GivenDef -ClassDef ::= id ClassConstr [Template] -ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses -ConstrMods ::= {Annotation} [AccessModifier] -ObjectDef ::= id [Template] -EnumDef ::= id ClassConstr InheritClauses EnumBody -GivenDef ::= [GivenSig] (AnnotType [‘=’ Expr] | StructuralInstance) -GivenSig ::= [id] [DefTypeParamClause] {UsingParamClause} ‘:’ -- one of `id`, `DefParamClause`, `UsingParamClause` must be present -StructuralInstance ::= ConstrApp {‘with’ ConstrApp} [‘with’ WithTemplateBody] -Extension ::= ‘extension’ [DefTypeParamClause] {UsingParamClause} - ‘(’ DefParam ‘)’ {UsingParamClause} ExtMethods -ExtMethods ::= ExtMethod | [nl] <<< ExtMethod {semi ExtMethod} >>> -ExtMethod ::= {Annotation [nl]} {Modifier} ‘def’ DefDef - | Export -Template ::= InheritClauses [TemplateBody] -InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}] -ConstrApps ::= ConstrApp ({‘,’ ConstrApp} | {‘with’ ConstrApp}) -ConstrApp ::= SimpleType1 {Annotation} {ParArgumentExprs} -ConstrExpr ::= SelfInvocation - | <<< SelfInvocation {semi BlockStat} >>> -SelfInvocation ::= ‘this’ ArgumentExprs {ArgumentExprs} - -WithTemplateBody ::= <<< [SelfType] TemplateStat {semi TemplateStat} >>> -TemplateBody ::= :<<< [SelfType] TemplateStat {semi TemplateStat} >>> -TemplateStat ::= Import - | Export - | {Annotation [nl]} {Modifier} Def - | {Annotation [nl]} {Modifier} Dcl - | Extension - | Expr1 - | EndMarker - | -SelfType ::= id [‘:’ InfixType] ‘=>’ - | ‘this’ ‘:’ InfixType ‘=>’ - -EnumBody ::= :<<< [SelfType] EnumStat {semi EnumStat} >>> -EnumStat ::= TemplateStat - | {Annotation [nl]} {Modifier} EnumCase -EnumCase ::= ‘case’ (id ClassConstr [‘extends’ ConstrApps]] | ids) - -TopStats ::= TopStat {semi TopStat} -TopStat ::= Import - | Export - | {Annotation [nl]} {Modifier} Def - | Extension - | Packaging - | PackageObject - | EndMarker - | -Packaging ::= ‘package’ QualId :<<< TopStats >>> -PackageObject ::= ‘package’ ‘object’ ObjectDef - -CompilationUnit ::= {‘package’ QualId semi} TopStats -```