@@ -8,6 +8,11 @@ use super::{
88 enums:: { enum_member_literals, enum_metadata} ,
99} ;
1010
11+ /// The result of evaluating a runtime comparison between two types.
12+ ///
13+ /// Definite truthiness is represented separately from a constraint for the operand currently being
14+ /// narrowed. A comparison can therefore be ambiguous at runtime while still constraining that
15+ /// operand in either branch.
1116#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
1217enum ComparisonResult < ' db > {
1318 /// The comparison always evaluates to true.
@@ -18,7 +23,7 @@ enum ComparisonResult<'db> {
1823 /// object of type `Literal[Foo.X]` in the following example, despite the fact that
1924 /// `Literal[1]` is disjoint from `Literal[Foo.X]`:
2025 ///
21- /// ```py
26+ /// ```python
2227 /// from enum import IntEnum
2328 ///
2429 /// class Foo(IntEnum):
@@ -43,6 +48,7 @@ enum ComparisonResult<'db> {
4348}
4449
4550impl < ' db > ComparisonResult < ' db > {
51+ /// Convert this result into a constraint for a branch with the given truthiness.
4652 fn constraint ( self , is_positive : bool ) -> Option < Type < ' db > > {
4753 match self {
4854 ComparisonResult :: AlwaysTrue => ( !is_positive) . then_some ( Type :: Never ) ,
@@ -52,6 +58,7 @@ impl<'db> ComparisonResult<'db> {
5258 }
5359 }
5460
61+ /// Preserve definite truthiness while discarding a conditional narrowing result.
5562 fn discard_narrowing ( self ) -> Self {
5663 match self {
5764 ComparisonResult :: CanNarrow ( _) => ComparisonResult :: Ambiguous ,
@@ -60,6 +67,10 @@ impl<'db> ComparisonResult<'db> {
6067 }
6168}
6269
70+ /// Return a constraint for `left` in a branch where `left == right` has the given truthiness.
71+ ///
72+ /// Returns `None` when the comparison behavior of either operand is not precise enough to safely
73+ /// constrain `left`.
6374pub ( super ) fn evaluate_type_equality < ' db > (
6475 db : & ' db dyn Db ,
6576 left : Type < ' db > ,
@@ -79,6 +90,10 @@ pub(super) fn evaluate_type_equality<'db>(
7990 } )
8091}
8192
93+ /// Return a constraint for `left` in a branch where `left != right` has the given truthiness.
94+ ///
95+ /// Returns `None` when the comparison behavior of either operand is not precise enough to safely
96+ /// constrain `left`.
8297pub ( super ) fn evaluate_type_inequality < ' db > (
8398 db : & ' db dyn Db ,
8499 left : Type < ' db > ,
@@ -96,6 +111,9 @@ pub(super) fn evaluate_type_inequality<'db>(
96111 . or_else ( || inequality_result ( db, left, right, is_positive) . constraint ( is_positive) )
97112}
98113
114+ /// Return the truthiness of `left == right` when it is known for every represented runtime value.
115+ ///
116+ /// A result that only permits narrowing remains ambiguous because it can still evaluate either way.
99117pub ( crate ) fn equality_truthiness < ' db > (
100118 db : & ' db dyn Db ,
101119 left : Type < ' db > ,
@@ -108,6 +126,10 @@ pub(crate) fn equality_truthiness<'db>(
108126 }
109127}
110128
129+ /// Evaluate equality recursively, treating `left` as the operand being constrained.
130+ ///
131+ /// `is_positive` selects the branch whose constraint is accumulated when either operand expands
132+ /// into multiple alternatives.
111133fn equality_result < ' db > (
112134 db : & ' db dyn Db ,
113135 left : Type < ' db > ,
@@ -280,12 +302,6 @@ fn equality_result<'db>(
280302 }
281303}
282304
283- /// Return a constraint that does not depend on the target's currently inferred literal union.
284- ///
285- /// Narrowing constraints participate in cyclic inference. Filtering `"B" | "C"` to `"B"` for the
286- /// false branch of `x == "C"` can freeze a loop before later iterations widen `x`. Constraining the
287- /// target with `~Literal["C"]` instead describes the predicate itself and remains valid as the cycle
288- /// reaches its fixed point.
289305fn is_builtin_primitive ( db : & dyn Db , ty : Type ) -> bool {
290306 match ty. resolve_type_alias ( db) {
291307 Type :: LiteralValue ( literal) => matches ! (
@@ -300,6 +316,15 @@ fn is_builtin_primitive(db: &dyn Db, ty: Type) -> bool {
300316 }
301317}
302318
319+ /// Return a predicate-shaped constraint for comparison with a primitive literal.
320+ ///
321+ /// Narrowing constraints participate in cyclic inference. Filtering `"B" | "C"` to `"B"` for the
322+ /// false branch of `x == "C"` can freeze a loop before later iterations widen `x`. Constraining the
323+ /// target with `~Literal["C"]` instead describes the predicate itself and remains valid as the cycle
324+ /// reaches its fixed point.
325+ ///
326+ /// The constraint also follows Python's equality between booleans and integers: `x != 0` excludes
327+ /// both `Literal[0]` and `Literal[False]`, while `x != 1` excludes `Literal[1]` and `Literal[True]`.
303328fn primitive_literal_constraint < ' db > (
304329 db : & ' db dyn Db ,
305330 left : Type < ' db > ,
@@ -381,6 +406,10 @@ fn primitive_literal_constraint<'db>(
381406 . then_some ( equal_to_right)
382407}
383408
409+ /// Return a direct enum-member constraint when the target is entirely from the same enum domain.
410+ ///
411+ /// This is only valid when the enum inherits comparison behavior that `ty` understands; custom
412+ /// equality or inequality methods make the result ambiguous.
384413fn enum_literal_constraint < ' db > (
385414 db : & ' db dyn Db ,
386415 left : Type < ' db > ,
@@ -425,6 +454,10 @@ fn is_same_enum_domain<'db>(db: &'db dyn Db, ty: Type<'db>, right: EnumLiteralTy
425454 }
426455}
427456
457+ /// Evaluate inequality recursively, treating `left` as the operand being constrained.
458+ ///
459+ /// `is_positive` selects the branch whose constraint is accumulated when either operand expands
460+ /// into multiple alternatives.
428461fn inequality_result < ' db > (
429462 db : & ' db dyn Db ,
430463 left : Type < ' db > ,
@@ -640,6 +673,10 @@ fn evaluate_union_left<'db>(
640673 } )
641674}
642675
676+ /// Combine comparison results for the alternatives of the union being constrained.
677+ ///
678+ /// Alternatives that cannot satisfy the selected branch are removed. Dynamic alternatives retain
679+ /// negative constraints for removed arms so that the result still describes the branch predicate.
643680fn evaluate_target_union < ' db > (
644681 db : & ' db dyn Db ,
645682 elements : & [ Type < ' db > ] ,
@@ -734,6 +771,10 @@ fn evaluate_union_right<'db>(
734771 )
735772}
736773
774+ /// Combine comparison results produced by alternatives of the non-target operand.
775+ ///
776+ /// The target remains possible when any alternative can satisfy the selected branch; definite
777+ /// truthiness is reported only when every alternative agrees.
737778fn evaluate_against_results < ' db > (
738779 db : & ' db dyn Db ,
739780 target : Type < ' db > ,
@@ -830,6 +871,10 @@ fn inequality_alternatives<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option<Vec<Ty
830871 finite_alternatives ( db, ty, ComparisonOperator :: Inequality )
831872}
832873
874+ /// Expand a type into its finite runtime alternatives when its comparison semantics are known.
875+ ///
876+ /// Enum classes with custom comparison methods are deliberately not expanded because their members
877+ /// may compare equal to values outside the enum domain.
833878fn finite_alternatives < ' db > (
834879 db : & ' db dyn Db ,
835880 ty : Type < ' db > ,
@@ -887,6 +932,7 @@ fn narrow_literal_comparison<'db>(
887932 }
888933}
889934
935+ /// Narrow `LiteralString` against a string-valued enum member with inherited `str` semantics.
890936fn narrow_literal_string_against_enum < ' db > (
891937 db : & ' db dyn Db ,
892938 enum_literal : EnumLiteralType < ' db > ,
@@ -1001,6 +1047,10 @@ impl ComparisonOperator {
10011047 }
10021048}
10031049
1050+ /// A known builtin implementation that determines the runtime behavior of a comparison.
1051+ ///
1052+ /// Two types with different known semantics cannot compare equal. Types with custom or otherwise
1053+ /// unknown comparison methods are not assigned a value of this enum.
10041054#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
10051055enum KnownComparisonSemantics {
10061056 Object ,
@@ -1067,6 +1117,9 @@ fn comparison_domain<'db>(
10671117 }
10681118}
10691119
1120+ /// Determine the builtin comparison implementation inherited by `ty`.
1121+ ///
1122+ /// Returns `None` when dunder lookup finds custom or conflicting comparison behavior.
10701123fn comparison_semantics < ' db > (
10711124 db : & ' db dyn Db ,
10721125 ty : Type < ' db > ,
@@ -1108,6 +1161,7 @@ fn comparison_semantics<'db>(
11081161 }
11091162}
11101163
1164+ /// Return whether `ty` is a singleton whose comparison uses object identity semantics.
11111165fn has_known_identity_comparison_semantics < ' db > (
11121166 db : & ' db dyn Db ,
11131167 ty : Type < ' db > ,
@@ -1243,6 +1297,10 @@ fn lookup_dunder<'db>(
12431297 )
12441298}
12451299
1300+ /// Return the comparison result for two literals when their runtime values determine it.
1301+ ///
1302+ /// This accounts for integer/boolean equality and enum aliases or enum values. `None` means custom
1303+ /// or insufficiently known comparison behavior prevents a definitive result.
12461304fn known_literal_equality < ' db > (
12471305 db : & ' db dyn Db ,
12481306 left : LiteralValueTypeKind < ' db > ,
@@ -1323,6 +1381,9 @@ fn known_type_value_equality<'db>(
13231381 )
13241382}
13251383
1384+ /// Return the statically known runtime value of an enum member.
1385+ ///
1386+ /// Custom enum construction can replace the declared value, so members of such enums return `None`.
13261387fn enum_literal_value < ' db > ( db : & ' db dyn Db , literal : EnumLiteralType < ' db > ) -> Option < Type < ' db > > {
13271388 let metadata = enum_metadata ( db, literal. enum_class ( db) ) ?;
13281389 let name = metadata. resolve_member ( literal. name ( db) ) ?;
@@ -1339,6 +1400,7 @@ fn enum_literal_value<'db>(db: &'db dyn Db, literal: EnumLiteralType<'db>) -> Op
13391400 }
13401401}
13411402
1403+ /// Return whether two enum literals resolve to the same member, including aliases.
13421404fn same_enum_member < ' db > (
13431405 db : & ' db dyn Db ,
13441406 left : EnumLiteralType < ' db > ,
0 commit comments