@@ -475,146 +475,6 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
475475 self . evaluate_simple_expr ( & expr_named. target , is_positive)
476476 }
477477
478- fn evaluate_expr_eq ( & mut self , lhs_ty : Type < ' db > , rhs_ty : Type < ' db > ) -> Option < Type < ' db > > {
479- // We can only narrow on equality checks against single-valued types.
480- if rhs_ty. is_single_valued ( self . db ) || rhs_ty. is_union_of_single_valued ( self . db ) {
481- // The fully-general (and more efficient) approach here would be to introduce a
482- // `NeverEqualTo` type that can wrap a single-valued type, and then simply return
483- // `~NeverEqualTo(rhs_ty)` here and let union/intersection builder sort it out. This is
484- // how we handle `AlwaysTruthy` and `AlwaysFalsy`. But this means we have to deal with
485- // this type everywhere, and possibly have it show up unsimplified in some cases, and
486- // so we instead prefer to just do the simplification here. (Another hybrid option that
487- // would be similar to this, but more efficient, would be to allow narrowing to return
488- // something that is not a type, and handle this not-a-type in `symbol_from_bindings`,
489- // instead of intersecting with a type.)
490-
491- // Return `true` if it is possible for any two inhabitants of the given types to
492- // compare equal to each other; otherwise return `false`.
493- fn could_compare_equal < ' db > (
494- db : & ' db dyn Db ,
495- left_ty : Type < ' db > ,
496- right_ty : Type < ' db > ,
497- ) -> bool {
498- if !left_ty. is_disjoint_from ( db, right_ty) {
499- // If types overlap, they have inhabitants in common; it's definitely possible
500- // for an object to compare equal to itself.
501- return true ;
502- }
503- match ( left_ty, right_ty) {
504- // In order to be sure a union type cannot compare equal to another type, it
505- // must be true that no element of the union can compare equal to that type.
506- ( Type :: Union ( union) , _) => union
507- . elements ( db)
508- . iter ( )
509- . any ( |ty| could_compare_equal ( db, * ty, right_ty) ) ,
510- ( _, Type :: Union ( union) ) => union
511- . elements ( db)
512- . iter ( )
513- . any ( |ty| could_compare_equal ( db, left_ty, * ty) ) ,
514- // Boolean literals and int literals are disjoint, and single valued, and yet
515- // `True == 1` and `False == 0`.
516- ( Type :: BooleanLiteral ( b) , Type :: IntLiteral ( i) )
517- | ( Type :: IntLiteral ( i) , Type :: BooleanLiteral ( b) ) => i64:: from ( b) == i,
518- // Other than the above cases, two single-valued disjoint types cannot compare
519- // equal.
520- _ => !( left_ty. is_single_valued ( db) && right_ty. is_single_valued ( db) ) ,
521- }
522- }
523-
524- // Return `true` if `lhs_ty` consists only of `LiteralString` and types that cannot
525- // compare equal to `rhs_ty`.
526- fn can_narrow_to_rhs < ' db > (
527- db : & ' db dyn Db ,
528- lhs_ty : Type < ' db > ,
529- rhs_ty : Type < ' db > ,
530- ) -> bool {
531- match lhs_ty {
532- Type :: Union ( union) => union
533- . elements ( db)
534- . iter ( )
535- . all ( |ty| can_narrow_to_rhs ( db, * ty, rhs_ty) ) ,
536- // Either `rhs_ty` is a string literal, in which case we can narrow to it (no
537- // other string literal could compare equal to it), or it is not a string
538- // literal, in which case (given that it is single-valued), LiteralString
539- // cannot compare equal to it.
540- Type :: LiteralString => true ,
541- _ => !could_compare_equal ( db, lhs_ty, rhs_ty) ,
542- }
543- }
544-
545- // Filter `ty` to just the types that cannot be equal to `rhs_ty`.
546- fn filter_to_cannot_be_equal < ' db > (
547- db : & ' db dyn Db ,
548- ty : Type < ' db > ,
549- rhs_ty : Type < ' db > ,
550- ) -> Type < ' db > {
551- match ty {
552- Type :: Union ( union) => {
553- union. map ( db, |ty| filter_to_cannot_be_equal ( db, * ty, rhs_ty) )
554- }
555- // Treat `bool` as `Literal[True, False]`.
556- Type :: NominalInstance ( instance)
557- if instance. class ( db) . is_known ( db, KnownClass :: Bool ) =>
558- {
559- UnionType :: from_elements (
560- db,
561- [ Type :: BooleanLiteral ( true ) , Type :: BooleanLiteral ( false ) ]
562- . into_iter ( )
563- . map ( |ty| filter_to_cannot_be_equal ( db, ty, rhs_ty) ) ,
564- )
565- }
566- // Treat enums as a union of their members.
567- Type :: NominalInstance ( instance)
568- if enum_metadata ( db, instance. class ( db) . class_literal ( db) . 0 ) . is_some ( ) =>
569- {
570- UnionType :: from_elements (
571- db,
572- enum_member_literals ( db, instance. class ( db) . class_literal ( db) . 0 , None )
573- . expect ( "Calling `enum_member_literals` on an enum class" )
574- . map ( |ty| filter_to_cannot_be_equal ( db, ty, rhs_ty) ) ,
575- )
576- }
577- _ => {
578- if ty. is_single_valued ( db) && !could_compare_equal ( db, ty, rhs_ty) {
579- ty
580- } else {
581- Type :: Never
582- }
583- }
584- }
585- }
586- Some ( if can_narrow_to_rhs ( self . db , lhs_ty, rhs_ty) {
587- rhs_ty
588- } else {
589- filter_to_cannot_be_equal ( self . db , lhs_ty, rhs_ty) . negate ( self . db )
590- } )
591- } else {
592- None
593- }
594- }
595-
596- fn evaluate_expr_ne ( & mut self , lhs_ty : Type < ' db > , rhs_ty : Type < ' db > ) -> Option < Type < ' db > > {
597- match ( lhs_ty, rhs_ty) {
598- ( Type :: NominalInstance ( instance) , Type :: IntLiteral ( i) )
599- if instance. class ( self . db ) . is_known ( self . db , KnownClass :: Bool ) =>
600- {
601- if i == 0 {
602- Some ( Type :: BooleanLiteral ( false ) . negate ( self . db ) )
603- } else if i == 1 {
604- Some ( Type :: BooleanLiteral ( true ) . negate ( self . db ) )
605- } else {
606- None
607- }
608- }
609- ( _, Type :: BooleanLiteral ( b) ) => Some (
610- UnionType :: from_elements ( self . db , [ rhs_ty, Type :: IntLiteral ( i64:: from ( b) ) ] )
611- . negate ( self . db ) ,
612- ) ,
613- _ if rhs_ty. is_single_valued ( self . db ) => Some ( rhs_ty. negate ( self . db ) ) ,
614- _ => None ,
615- }
616- }
617-
618478 fn evaluate_expr_in ( & mut self , lhs_ty : Type < ' db > , rhs_ty : Type < ' db > ) -> Option < Type < ' db > > {
619479 if lhs_ty. is_single_valued ( self . db ) || lhs_ty. is_union_of_single_valued ( self . db ) {
620480 rhs_ty
@@ -713,8 +573,8 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
713573 }
714574 }
715575 ast:: CmpOp :: Is => Some ( rhs_ty) ,
716- ast:: CmpOp :: Eq => self . evaluate_expr_eq ( lhs_ty, rhs_ty) ,
717- ast:: CmpOp :: NotEq => self . evaluate_expr_ne ( lhs_ty, rhs_ty) ,
576+ ast:: CmpOp :: Eq => self . evaluate_expr_in ( lhs_ty, rhs_ty) ,
577+ ast:: CmpOp :: NotEq => self . evaluate_expr_not_in ( lhs_ty, rhs_ty) ,
718578 ast:: CmpOp :: In => self . evaluate_expr_in ( lhs_ty, rhs_ty) ,
719579 ast:: CmpOp :: NotIn => self . evaluate_expr_not_in ( lhs_ty, rhs_ty) ,
720580 _ => None ,
0 commit comments