Skip to content

Commit 47ec229

Browse files
authored
Spec: Opaque type aliases. (#17947)
[skip ci] Based on #17940.
2 parents be70d46 + 229738f commit 47ec229

File tree

4 files changed

+73
-133
lines changed

4 files changed

+73
-133
lines changed

docs/_spec/03-types.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,11 @@ We define `memberType(´T´, ´id´, ´p´)` as follows:
10121012
- If ´m´ is not defined, the result is undefined.
10131013
- If ´m´ is a class declaration, the result is a class result with class ´m´.
10141014
- If ´m´ is a term definition in class ´D´ with declared type ´U´, the result is a term result with underlying type [`asSeenFrom`](#as-seen-from)`(´U´, ´D´, ´p´)` and stable flag true if and only if ´m´ is stable.
1015-
- If ´m´ is a type member definition in class ´D´ with declared type definition ´U´, the result is a type result with underlying type definition [`asSeenFrom`](#as-seen-from)`(´U´, ´D´, ´p´)`.
1015+
- If ´m´ is a type member definition in class ´D´, the result is a type result with underlying type definition [`asSeenFrom`](#as-seen-from)`(´U´, ´D´, ´p´)` where ´U´ is defined as follows:
1016+
- If ´m´ is an opaque type alias member definition with declared definition ´>: L <: H = V´, then
1017+
- ´U´ is ´= V´ if `´p = D.´this` or if we are computing `memberType` in a [_transparent mode_](#type-erasure),
1018+
- ´U´ is ´>: L <: H´ otherwise.
1019+
- ´U´ is the declared type definition of ´m´ otherwise.
10161020
- If ´T´ is another monomorphic type designator of the form ´q.X´:
10171021
- Let ´U´ be `memberType(´q´, ´X´)`
10181022
- Let ´H´ be the upper bound of ´U´
@@ -1228,6 +1232,7 @@ A type is called _generic_ if it contains type arguments or type variables.
12281232
_Type erasure_ is a mapping from (possibly generic) types to non-generic types.
12291233
We write ´|T|´ for the erasure of type ´T´.
12301234
The erasure mapping is defined as follows.
1235+
Internal computations are performed in a _transparent mode_, which has an effect on how [`memberType`](#member-type) behaves for opaque type aliases.
12311236

12321237
- The erasure of `AnyKind` is `Object`.
12331238
- The erasure of a non-class type designator is the erasure of its underlying upper bound.

docs/_spec/04-basic-declarations-and-definitions.md

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ PatVarDef ::= ‘val’ PatDef
1616
Def ::= PatVarDef
1717
| ‘def’ FunDef
1818
| ‘type’ {nl} TypeDef
19+
| ‘opaque‘ ‘type‘ {nl} OpaqueTypeDef
1920
| TmplDef
2021
```
2122

@@ -218,17 +219,21 @@ A variable definition `var ´x_1, ..., x_n: T´ = ´e´` is a shorthand for the
218219
## Type Declarations and Type Aliases
219220

220221
```ebnf
221-
Dcl ::= ‘type’ {nl} TypeDcl
222-
TypeDcl ::= id [TypeParamClause] [‘>:’ Type] [‘<:’ Type]
223-
Def ::= ‘type’ {nl} TypeDef
224-
TypeDef ::= id [TypeParamClause] ‘=’ Type
222+
Dcl ::= ‘type’ {nl} TypeDcl
223+
TypeDcl ::= id [TypeParamClause] [‘>:’ Type] [‘<:’ Type]
224+
Def ::= ‘type’ {nl} TypeDef
225+
| ‘opaque‘ ‘type‘ {nl} OpaqueTypeDef
226+
TypeDef ::= id [TypeParamClause] ‘=’ Type
227+
OpaqueTypeDef ::= id [TypeParamClause] [‘>:’ Type] [‘<:’ Type] ‘=’ Type
225228
```
226229

227230
A possibly parameterized _type declaration_ `type ´t´[´\mathit{tps}\,´] >: ´L´ <: ´H´` declares ´t´ to be an abstract type.
228231
If omitted, ´L´ and ´H´ are implied to be `Nothing` and `scala.Any`, respectively.
229232

230233
A possibly parameterized _type alias_ `type ´t´[´\mathit{tps}\,´] = ´T´` defines ´t´ to be a concrete type member.
231234

235+
A possibly parameterized _opaque type alias_ `opaque type ´t´[´\mathit{tps}\,´] >: ´L´ <: ´H´ = ´T´` defines ´t´ to be an opaque type alias with public bounds `>: ´L´ <: ´H´` and a private alias `= ´T´`.
236+
232237
If a type parameter clause `[´\mathit{tps}\,´]` is present, it is desugared away according to the rules in the following section.
233238

234239
### Desugaring of parameterized type declarations
@@ -248,7 +253,7 @@ A parameterized abstract type
248253
```scala
249254
type ´t´[´\mathit{tps}\,´] >: ´L´ <: ´H´
250255
```
251-
is desugared into an unparameterized abstract type as follow:
256+
is desugared into an unparameterized abstract type as follows:
252257
- If `L` conforms to `Nothing`, then,
253258

254259
```scala
@@ -286,6 +291,25 @@ type ´t´ = [´\mathit{tps'}\,´] =>> ´T´
286291
```
287292
where ´\mathit{tps'}´ is computed as in the previous case.
288293

294+
#### Opaque Type Alias
295+
296+
A parameterized type alias
297+
```scala
298+
type ´t´[´\mathit{tps}\,´] >: ´L´ <: ´H´ = ´T´
299+
```
300+
is desugared into an unparameterized opaque type alias as follows:
301+
- If `L` conforms to `Nothing`, then,
302+
303+
```scala
304+
type ´t´ >: Nothing <:\mathit{tps'}\,´] =>> ´H´ = [´\mathit{tps'}\,´] =>> ´T´
305+
```
306+
- otherwise,
307+
308+
```scala
309+
type ´t´ >:\mathit{tps'}\,´] =>> ´L´ <: [´\mathit{tps'}\,´] =>> ´H´ =\mathit{tps'}\,´] =>> ´T´
310+
```
311+
where ´\mathit{tps'}´ is computed as in the previous cases.
312+
289313
### Non-Parameterized Type Declarations and Type Aliases
290314

291315
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´.
@@ -295,6 +319,19 @@ It is a compile-time error if ´L´ does not conform to ´H´.
295319

296320
A _type alias_ `type ´t´ = ´T´` defines ´t´ to be an alias name for the type ´T´.
297321

322+
An _opaque type alias_ `opaque type ´t´ >: ´L´ <: ´H´ = ´T´` defines ´t´ to be an opaque type alias with public bounds `>: ´L´ <: ´H´` and a private alias `= ´T´`.
323+
An opaque type alias can only be declared within a [template](./05-classes-and-objects.html#templates).
324+
It cannot be `private` and cannot be overridden in subclasses.
325+
In order for the definition to be valid, ´T´ must satisfy some constraints:
326+
327+
- ´L <: T´ and ´T <: H´ must be true,
328+
- ´T´ must not be a context function type, and
329+
- If ´T´ is a type lambda, its result must be a proper type (i.e., it cannot be a curried type lambda).
330+
331+
When viewed from within its enclosing template, an opaque type alias behaves as a type alias with type definition `= ´T´`.
332+
When viewed from anywhere else, it behaves as a type declaration with type definition `>: ´L´ <: ´H´`.
333+
See [`memberType`](./03-types.html#member-type) for the precise mechanism that governs this dual view.
334+
298335
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.
299336
However, it is a static error if a type alias refers recursively to the defined type itself.
300337
That is, the type ´T´ in a type alias `type ´t´[´\mathit{tps}\,´] = ´T´` may not refer directly or indirectly to the name ´t´.

docs/_spec/TODOreference/other-new-features/opaques.md renamed to docs/_spec/APPLIEDreference/other-new-features/opaques.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,28 @@ l1.mul(x, z) // error: found l2.Logarithm, required l1.Logarithm
176176
```
177177
In general, one can think of an opaque type as being only transparent in the scope of `private[this]`.
178178

179-
[More details](opaques-details.md)
179+
## Top-level Opaque Types
180+
181+
An opaque type alias on the top-level is transparent in all other top-level definitions in the sourcefile where it appears, but is opaque in nested
182+
objects and classes and in all other source files. Example:
183+
```scala
184+
// in test1.scala
185+
opaque type A = String
186+
val x: A = "abc"
187+
188+
object obj:
189+
val y: A = "abc" // error: found: "abc", required: A
190+
191+
// in test2.scala
192+
def z: String = x // error: found: A, required: String
193+
```
194+
This behavior becomes clear if one recalls that top-level definitions are placed in their own synthetic object. For instance, the code in `test1.scala` would expand to
195+
```scala
196+
object test1$package:
197+
opaque type A = String
198+
val x: A = "abc"
199+
200+
object obj:
201+
val y: A = "abc" // error: cannot assign "abc" to opaque type alias A
202+
```
203+
The opaque type alias `A` is transparent in its scope, which includes the definition of `x`, but not the definitions of `obj` and `y`.

docs/_spec/TODOreference/other-new-features/opaques-details.md

Lines changed: 0 additions & 126 deletions
This file was deleted.

0 commit comments

Comments
 (0)