@@ -7,8 +7,8 @@ use crate::semantic_index::expression::Expression;
77use crate :: semantic_index:: symbol:: { ScopeId , ScopedSymbolId , SymbolTable } ;
88use crate :: semantic_index:: symbol_table;
99use crate :: types:: {
10- infer_expression_types, ClassLiteralType , IntersectionBuilder , KnownClass ,
11- KnownConstraintFunction , KnownFunction , Truthiness , Type , UnionBuilder ,
10+ infer_expression_types, ClassBase , ClassLiteralType , IntersectionBuilder , KnownClass ,
11+ KnownFunction , SubclassOfType , Truthiness , Type , UnionBuilder ,
1212} ;
1313use crate :: Db ;
1414use itertools:: Itertools ;
@@ -83,27 +83,37 @@ fn all_negative_narrowing_constraints_for_expression<'db>(
8383 NarrowingConstraintsBuilder :: new ( db, ConstraintNode :: Expression ( expression) , false ) . finish ( )
8484}
8585
86- /// Generate a constraint from the type of a `classinfo` argument to `isinstance` or `issubclass`.
87- ///
88- /// The `classinfo` argument can be a class literal, a tuple of (tuples of) class literals. PEP 604
89- /// union types are not yet supported. Returns `None` if the `classinfo` argument has a wrong type.
90- fn generate_classinfo_constraint < ' db > (
91- db : & ' db dyn Db ,
92- classinfo : & Type < ' db > ,
93- constraint_fn : KnownConstraintFunction ,
94- ) -> Option < Type < ' db > > {
95- match classinfo {
96- Type :: Tuple ( tuple) => {
97- let mut builder = UnionBuilder :: new ( db) ;
98- for element in tuple. elements ( db) {
99- builder = builder. add ( generate_classinfo_constraint ( db, element, constraint_fn) ?) ;
86+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
87+ pub enum KnownConstraintFunction {
88+ /// `builtins.isinstance`
89+ IsInstance ,
90+ /// `builtins.issubclass`
91+ IsSubclass ,
92+ }
93+
94+ impl KnownConstraintFunction {
95+ /// Generate a constraint from the type of a `classinfo` argument to `isinstance` or `issubclass`.
96+ ///
97+ /// The `classinfo` argument can be a class literal, a tuple of (tuples of) class literals. PEP 604
98+ /// union types are not yet supported. Returns `None` if the `classinfo` argument has a wrong type.
99+ fn generate_constraint < ' db > ( self , db : & ' db dyn Db , classinfo : Type < ' db > ) -> Option < Type < ' db > > {
100+ match classinfo {
101+ Type :: Tuple ( tuple) => {
102+ let mut builder = UnionBuilder :: new ( db) ;
103+ for element in tuple. elements ( db) {
104+ builder = builder. add ( self . generate_constraint ( db, * element) ?) ;
105+ }
106+ Some ( builder. build ( ) )
100107 }
101- Some ( builder. build ( ) )
102- }
103- Type :: ClassLiteral ( ClassLiteralType { class } ) => {
104- Some ( constraint_fn. apply_constraint ( * class) )
108+ Type :: ClassLiteral ( ClassLiteralType { class } )
109+ | Type :: SubclassOf ( SubclassOfType {
110+ base : ClassBase :: Class ( class) ,
111+ } ) => Some ( match self {
112+ KnownConstraintFunction :: IsInstance => Type :: instance ( class) ,
113+ KnownConstraintFunction :: IsSubclass => Type :: subclass_of ( class) ,
114+ } ) ,
115+ _ => None ,
105116 }
106- _ => None ,
107117 }
108118}
109119
@@ -428,11 +438,13 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
428438 let class_info_ty =
429439 inference. expression_ty ( class_info. scoped_expression_id ( self . db , scope) ) ;
430440
431- generate_classinfo_constraint ( self . db , & class_info_ty, function) . map ( |constraint| {
432- let mut constraints = NarrowingConstraints :: default ( ) ;
433- constraints. insert ( symbol, constraint. negate_if ( self . db , !is_positive) ) ;
434- constraints
435- } )
441+ function
442+ . generate_constraint ( self . db , class_info_ty)
443+ . map ( |constraint| {
444+ let mut constraints = NarrowingConstraints :: default ( ) ;
445+ constraints. insert ( symbol, constraint. negate_if ( self . db , !is_positive) ) ;
446+ constraints
447+ } )
436448 }
437449 // for the expression `bool(E)`, we further narrow the type based on `E`
438450 Type :: ClassLiteral ( class_type)
0 commit comments