@@ -3204,18 +3204,32 @@ impl<'db> TypeInferenceBuilder<'db> {
3204
3204
// f(T_inter) = f(P1) & f(P2) & ... & f(Pn)
3205
3205
//
3206
3206
// The reason for this is the following: In general, for any function 'f', the
3207
- // set f(A) & f(B) can be *larger than* the set f(A & B). This means that we
3208
- // will return a type that is too wide, which is not necessarily problematic.
3207
+ // set f(A) & f(B) is *larger than or equal to* the set f(A & B). This means
3208
+ // that we will return a type that is possibly wider than it could be, but
3209
+ // never wrong.
3209
3210
//
3210
3211
// However, we do have to leave out the negative contributions. If we were to
3211
3212
// add a contribution like ~f(N1), we would potentially infer result types
3212
- // that are too narrow, since ~f(A) can be larger than f(~A) .
3213
+ // that are too narrow.
3213
3214
//
3214
3215
// As an example for this, consider the intersection type `int & ~Literal[1]`.
3215
3216
// If 'f' would be the `==`-comparison with 2, we obviously can't tell if that
3216
- // answer would be true or false, so we need to return `bool`. However, if we
3217
- // compute f(int) & ~f(Literal[1]), we get `bool & ~Literal[False]`, which can
3218
- // be simplified to `Literal[True]` -- a type that is too narrow.
3217
+ // answer would be true or false, so we need to return `bool`. And indeed, we
3218
+ // we have (glossing over notational details):
3219
+ //
3220
+ // f(int & ~1)
3221
+ // = f({..., -1, 0, 2, 3, ...})
3222
+ // = {..., False, False, True, False, ...}
3223
+ // = bool
3224
+ //
3225
+ // On the other hand, if we were to compute
3226
+ //
3227
+ // f(int) & ~f(1)
3228
+ // = bool & ~False
3229
+ // = True
3230
+ //
3231
+ // we would get a result type `Literal[True]` which is too narrow.
3232
+ //
3219
3233
let mut builder = IntersectionBuilder :: new ( self . db ) ;
3220
3234
for pos in intersection. positive ( self . db ) {
3221
3235
let result = match intersection_on {
0 commit comments