@@ -72,6 +72,10 @@ a non-union type, for this purpose we define the _join_ of a union type `T1 |
72
72
` T1 ` ,...,` Tn ` . Note that union types might still appear as type arguments in the
73
73
resulting type, this guarantees that the join is always finite.
74
74
75
+ The _ visible join_ of a union type is its join where all operands of the intersection that
76
+ are instances of [ transparent] ( ../other-new-features/transparent-traits.md ) traits or classes are removed.
77
+
78
+
75
79
### Example
76
80
77
81
Given
@@ -80,31 +84,50 @@ Given
80
84
trait C [+ T ]
81
85
trait D
82
86
trait E
83
- class A extends C [A ] with D
84
- class B extends C [B ] with D with E
87
+ transparent trait X
88
+ class A extends C [A ], D , X
89
+ class B extends C [B ], D , E , X
85
90
```
86
91
87
- The join of ` A | B ` is ` C[A | B] & D `
92
+ The join of ` A | B ` is ` C[A | B] & D & X ` and the visible join of ` A | B ` is ` C[A | B] & D ` .
93
+
94
+ ## Hard and Soft Union Types
95
+
96
+ We distinguish between hard and soft union types. A _ hard_ union type is a union type that's explicitly
97
+ written in the source. For instance, in
98
+ ``` scala
99
+ val x : Int | String = ...
100
+ ```
101
+ ` Int | String ` would be a hard union type. A _ soft_ union type is a type that arises from type checking
102
+ an alternative of expressions. For instance, the type of the expression
103
+ ``` scala
104
+ val x = 1
105
+ val y = " abc"
106
+ if cond then x else y
107
+ ```
108
+ is the soft unon type ` Int | String ` . Similarly for match expressions. The type of
109
+ ``` scala
110
+ x match
111
+ case 1 => x
112
+ case 2 => " abc"
113
+ case 3 => List (1 , 2 , 3 )
114
+ ```
115
+ is the soft union type ` Int | "abc" | List[Int] ` .
116
+
88
117
89
118
## Type inference
90
119
91
120
When inferring the result type of a definition (` val ` , ` var ` , or ` def ` ) and the
92
- type we are about to infer is a union type, then we replace it by its join.
121
+ type we are about to infer is a soft union type, then we replace it by its visible join,
122
+ provided it is not empty.
93
123
Similarly, when instantiating a type argument, if the corresponding type
94
124
parameter is not upper-bounded by a union type and the type we are about to
95
- instantiate is a union type, we replace it by its join. This mirrors the
125
+ instantiate is a soft union type, we replace it by its visible join, provided it is not empty.
126
+ This mirrors the
96
127
treatment of singleton types which are also widened to their underlying type
97
128
unless explicitly specified. The motivation is the same: inferring types
98
129
which are "too precise" can lead to unintuitive typechecking issues later on.
99
130
100
- ** Note:** Since this behavior limits the usability of union types, it might
101
- be changed in the future. For example by not widening unions that have been
102
- explicitly written down by the user and not inferred, or by not widening a type
103
- argument when the corresponding type parameter is covariant.
104
-
105
- See [ PR #2330 ] ( https://github.com/lampepfl/dotty/pull/2330 ) and
106
- [ Issue #4867 ] ( https://github.com/lampepfl/dotty/issues/4867 ) for further discussions.
107
-
108
131
### Example
109
132
110
133
``` scala
0 commit comments