From 62d4bc83330bdd1994c3c4137b6dafc8984d2ad2 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 3 Apr 2017 04:28:45 -0700 Subject: [PATCH] Allow variables inside isinstance (#3070) Fixes #3068 This would allow the use of variables inside the second argument to isinstance/issubclass, as long as those variables are assigned a tuple of types in a "visible range". --- mypy/binder.py | 6 ++---- mypy/checker.py | 10 +++++++++- test-data/unit/check-isinstance.test | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/mypy/binder.py b/mypy/binder.py index 55f02179cf65..24fb37555698 100644 --- a/mypy/binder.py +++ b/mypy/binder.py @@ -110,8 +110,7 @@ def _get(self, key: Key, index: int=-1) -> Type: return None def put(self, expr: Expression, typ: Type) -> None: - # TODO: replace with isinstance(expr, BindableTypes) - if not isinstance(expr, (IndexExpr, MemberExpr, NameExpr)): + if not isinstance(expr, BindableTypes): return if not expr.literal: return @@ -203,8 +202,7 @@ def assign_type(self, expr: Expression, type: Type, declared_type: Type, restrict_any: bool = False) -> None: - # TODO: replace with isinstance(expr, BindableTypes) - if not isinstance(expr, (IndexExpr, MemberExpr, NameExpr)): + if not isinstance(expr, BindableTypes): return None if not expr.literal: return diff --git a/mypy/checker.py b/mypy/checker.py index 5f68357db55b..431d2d38aabe 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -2756,8 +2756,16 @@ def flatten(t: Expression) -> List[Expression]: return [t] +def flatten_types(t: Type) -> List[Type]: + """Flatten a nested sequence of tuples into one list of nodes.""" + if isinstance(t, TupleType): + return [b for a in t.items for b in flatten_types(a)] + else: + return [t] + + def get_isinstance_type(expr: Expression, type_map: Dict[Expression, Type]) -> List[TypeRange]: - all_types = [type_map[e] for e in flatten(expr)] + all_types = flatten_types(type_map[expr]) types = [] # type: List[TypeRange] for type in all_types: if isinstance(type, FunctionLike) and type.is_type_obj(): diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index 973d463d6085..6bd2ef879dd6 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -1412,3 +1412,19 @@ def f(x: Union[int, A], a: Type[A]) -> None: [builtins fixtures/isinstancelist.pyi] + +[case testIsinstanceVariableSubstitution] +T = (int, str) +U = (list, T) +x: object = None + +if isinstance(x, T): + reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]' + +if isinstance(x, U): + reveal_type(x) # E: Revealed type is 'Union[builtins.list[Any], builtins.int, builtins.str]' + +if isinstance(x, (set, (list, T))): + reveal_type(x) # E: Revealed type is 'Union[builtins.set[Any], builtins.list[Any], builtins.int, builtins.str]' + +[builtins fixtures/isinstancelist.pyi]