diff --git a/mypy/binder.py b/mypy/binder.py index d3482d1dad4f..3c4e3f11aba8 100644 --- a/mypy/binder.py +++ b/mypy/binder.py @@ -385,7 +385,7 @@ def assign_type(self, expr: Expression, type: Type, declared_type: Type | None) p_declared = get_proper_type(declared_type) p_type = get_proper_type(type) - if isinstance(p_type, AnyType): + if isinstance(p_type, AnyType) and not p_type.is_special_form: # Any type requires some special casing, for both historical reasons, # and to optimise user experience without sacrificing correctness too much. if isinstance(expr, RefExpr) and isinstance(expr.node, Var) and expr.node.is_inferred: diff --git a/mypy/checker.py b/mypy/checker.py index 2195c10e2fec..25061b215e26 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5092,6 +5092,9 @@ def visit_try_without_finally(self, s: TryStmt, try_frame: bool) -> None: # To support local variables, we make this a definition line, # causing assignment to set the variable's type. var.is_inferred_def = True + # In case current node was deferred, start from blank slate. + if isinstance(var.node, Var): + var.node.type = None self.check_assignment(var, self.temp_node(t, var)) self.accept(s.handlers[i]) var = s.vars[i] diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 0804917476a9..4d6353c928be 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -2865,7 +2865,7 @@ def infer_overload_return_type( matches: list[CallableType] = [] return_types: list[Type] = [] inferred_types: list[Type] = [] - args_contain_any = any(map(has_any_type, arg_types)) + args_contain_any = any(has_any_type(a, include_special_form=True) for a in arg_types) type_maps: list[dict[Expression, Type]] = [] for typ in plausible_targets: @@ -5977,7 +5977,7 @@ def accept( ): self.msg.disallowed_any_type(typ, node) - if not self.chk.in_checked_function() or self.chk.current_node_deferred: + if not self.chk.in_checked_function(): result: Type = AnyType(TypeOfAny.unannotated) else: result = typ @@ -6311,18 +6311,29 @@ def has_abstract_type(self, caller_type: ProperType, callee_type: ProperType) -> ) -def has_any_type(t: Type, ignore_in_type_obj: bool = False) -> bool: +def has_any_type( + t: Type, ignore_in_type_obj: bool = False, include_special_form: bool = False +) -> bool: """Whether t contains an Any type""" - return t.accept(HasAnyType(ignore_in_type_obj)) + return t.accept(HasAnyType(ignore_in_type_obj, include_special_form)) class HasAnyType(types.BoolTypeQuery): - def __init__(self, ignore_in_type_obj: bool) -> None: + def __init__(self, ignore_in_type_obj: bool, include_special_form: bool) -> None: super().__init__(types.ANY_STRATEGY) self.ignore_in_type_obj = ignore_in_type_obj + self.include_special_form = include_special_form def visit_any(self, t: AnyType) -> bool: - return t.type_of_any != TypeOfAny.special_form # special forms are not real Any types + if self.include_special_form: + return True + return not t.is_special_form # special forms are not real Any types + + def visit_tuple_type(self, t: TupleType) -> bool: + types = t.items.copy() + if t.partial_fallback.type.fullname != "builtins.tuple": + types += [t.partial_fallback] + return self.query_types(types) def visit_callable_type(self, t: CallableType) -> bool: if self.ignore_in_type_obj and t.is_type_obj(): @@ -6547,7 +6558,7 @@ def any_causes_overload_ambiguity( # We ignore Anys in type object callables as ambiguity # creators, since that can lead to falsely claiming ambiguity # for overloads between Type and Callable. - if has_any_type(arg_type, ignore_in_type_obj=True): + if has_any_type(arg_type, ignore_in_type_obj=True, include_special_form=True): matching_formals_unfiltered = [ (item_idx, lookup[arg_idx]) for item_idx, lookup in enumerate(actual_to_formal) diff --git a/mypy/plugins/proper_plugin.py b/mypy/plugins/proper_plugin.py index f51685c80afa..49ba633c4569 100644 --- a/mypy/plugins/proper_plugin.py +++ b/mypy/plugins/proper_plugin.py @@ -58,8 +58,9 @@ def isinstance_proper_hook(ctx: FunctionContext) -> Type: right = get_proper_type(ctx.arg_types[1][0]) for arg in ctx.arg_types[0]: + p_arg = get_proper_type(arg) if ( - is_improper_type(arg) or isinstance(get_proper_type(arg), AnyType) + is_improper_type(arg) or isinstance(p_arg, AnyType) and not p_arg.is_special_form ) and is_dangerous_target(right): if is_special_target(right): return ctx.default_return_type diff --git a/mypy/types.py b/mypy/types.py index 41a958ae93cc..469b67ec3436 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -1160,6 +1160,15 @@ def __init__( def is_from_error(self) -> bool: return self.type_of_any == TypeOfAny.from_error + @property + def is_special_form(self) -> bool: + if self.type_of_any == TypeOfAny.special_form: + return True + if self.type_of_any == TypeOfAny.from_another_any: + assert self.source_any is not None + return self.source_any.type_of_any == TypeOfAny.special_form + return False + def accept(self, visitor: TypeVisitor[T]) -> T: return visitor.visit_any(self) diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index 243568c54253..eac846c53197 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -5219,7 +5219,7 @@ _R = TypeVar('_R') @overload def partial(__func: Callable[[_T], _S], __arg: _T) -> Callable[[], _S]: ... @overload -def partial(__func: Callable[[_T, _S], _S], __arg: _T) -> Callable[[_S], _R]: ... +def partial(__func: Callable[[_T, _S], _R], __arg: _T) -> Callable[[_S], _R]: ... def partial(*args: Any) -> Any: pass diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index a40aa21ff26a..9346a929d601 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -630,7 +630,7 @@ class Child(Parent): def bar(self) -> int: if 1: - self = super(Child, self).something() + # self = super(Child, self).something() reveal_type(self) # N: Revealed type is "__main__.Child" if self is None: reveal_type(self)