22
33from typing import Iterable , List , Optional
44
5+ from mypy import experiments
56from mypy .types import (
67 CallableType , Type , TypeVisitor , UnboundType , AnyType , Void , NoneTyp , TypeVarType ,
78 Instance , TupleType , TypedDictType , UnionType , Overloaded , ErasedType , PartialType ,
8- DeletedType , UninhabitedType , TypeType , TypeVarId , is_named_instance
9+ DeletedType , UninhabitedType , TypeType , TypeVarId , TypeQuery , ALL_TYPES_STRATEGY ,
10+ is_named_instance
911)
1012from mypy .maptype import map_instance_to_supertype
1113from mypy import nodes
@@ -149,13 +151,23 @@ def infer_constraints(template: Type, actual: Type,
149151 # be a supertype of the potential subtype, some item of the Union
150152 # must be a supertype of it.
151153 if direction == SUBTYPE_OF and isinstance (actual , UnionType ):
154+ # If some of items is not a complete type, disregard that.
155+ items = simplify_away_incomplete_types (actual .items )
156+ # We infer constraints eagerly -- try to find constraints for a type
157+ # variable if possible. This seems to help with some real-world
158+ # use cases.
152159 return any_constraints (
153160 [infer_constraints_if_possible (template , a_item , direction )
154- for a_item in actual .items ])
161+ for a_item in items ],
162+ eager = True )
155163 if direction == SUPERTYPE_OF and isinstance (template , UnionType ):
164+ # When the template is a union, we are okay with leaving some
165+ # type variables indeterminate. This helps with some special
166+ # cases, though this isn't very principled.
156167 return any_constraints (
157168 [infer_constraints_if_possible (t_item , actual , direction )
158- for t_item in template .items ])
169+ for t_item in template .items ],
170+ eager = False )
159171
160172 # Remaining cases are handled by ConstraintBuilderVisitor.
161173 return template .accept (ConstraintBuilderVisitor (actual , direction ))
@@ -177,12 +189,18 @@ def infer_constraints_if_possible(template: Type, actual: Type,
177189 return infer_constraints (template , actual , direction )
178190
179191
180- def any_constraints (options : List [Optional [List [Constraint ]]]) -> List [Constraint ]:
181- """Deduce what we can from a collection of constraint lists given that
182- at least one of the lists must be satisfied. A None element in the
183- list of options represents an unsatisfiable constraint and is ignored.
192+ def any_constraints (options : List [Optional [List [Constraint ]]], eager : bool ) -> List [Constraint ]:
193+ """Deduce what we can from a collection of constraint lists.
194+
195+ It's a given that at least one of the lists must be satisfied. A
196+ None element in the list of options represents an unsatisfiable
197+ constraint and is ignored. Ignore empty constraint lists if eager
198+ is true -- they are always trivially satisfiable.
184199 """
185- valid_options = [option for option in options if option is not None ]
200+ if eager :
201+ valid_options = [option for option in options if option ]
202+ else :
203+ valid_options = [option for option in options if option is not None ]
186204 if len (valid_options ) == 1 :
187205 return valid_options [0 ]
188206 # Otherwise, there are either no valid options or multiple valid options.
@@ -196,6 +214,34 @@ def any_constraints(options: List[Optional[List[Constraint]]]) -> List[Constrain
196214 # every option, combine the bounds with meet/join.
197215
198216
217+ def simplify_away_incomplete_types (types : List [Type ]) -> List [Type ]:
218+ complete = [typ for typ in types if is_complete_type (typ )]
219+ if complete :
220+ return complete
221+ else :
222+ return types
223+
224+
225+ def is_complete_type (typ : Type ) -> bool :
226+ """Is a type complete?
227+
228+ A complete doesn't have uninhabited type components or (when not in strict
229+ optional mode) None components.
230+ """
231+ return typ .accept (CompleteTypeVisitor ())
232+
233+
234+ class CompleteTypeVisitor (TypeQuery ):
235+ def __init__ (self ) -> None :
236+ super ().__init__ (default = True , strategy = ALL_TYPES_STRATEGY )
237+
238+ def visit_none_type (self , t : NoneTyp ) -> bool :
239+ return experiments .STRICT_OPTIONAL
240+
241+ def visit_uninhabited_type (self , t : UninhabitedType ) -> bool :
242+ return False
243+
244+
199245class ConstraintBuilderVisitor (TypeVisitor [List [Constraint ]]):
200246 """Visitor class for inferring type constraints."""
201247
0 commit comments