@@ -3204,18 +3204,32 @@ impl<'db> TypeInferenceBuilder<'db> {
32043204 // f(T_inter) = f(P1) & f(P2) & ... & f(Pn)
32053205 //
32063206 // 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.
32093210 //
32103211 // However, we do have to leave out the negative contributions. If we were to
32113212 // 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.
32133214 //
32143215 // As an example for this, consider the intersection type `int & ~Literal[1]`.
32153216 // 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+ //
32193233 let mut builder = IntersectionBuilder :: new ( self . db ) ;
32203234 for pos in intersection. positive ( self . db ) {
32213235 let result = match intersection_on {
0 commit comments