@@ -72,6 +72,10 @@ a non-union type, for this purpose we define the _join_ of a union type `T1 |
7272` T1 ` ,...,` Tn ` . Note that union types might still appear as type arguments in the
7373resulting type, this guarantees that the join is always finite.
7474
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+
7579### Example
7680
7781Given
@@ -80,31 +84,50 @@ Given
8084trait C [+ T ]
8185trait D
8286trait 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
8590```
8691
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+
88117
89118## Type inference
90119
91120When 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.
93123Similarly, when instantiating a type argument, if the corresponding type
94124parameter 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
96127treatment of singleton types which are also widened to their underlying type
97128unless explicitly specified. The motivation is the same: inferring types
98129which are "too precise" can lead to unintuitive typechecking issues later on.
99130
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-
108131### Example
109132
110133``` scala
0 commit comments