|
196 | 196 | LiteralType, |
197 | 197 | NoneType, |
198 | 198 | Overloaded, |
| 199 | + Parameters, |
| 200 | + ParamSpecType, |
199 | 201 | PartialType, |
200 | 202 | ProperType, |
201 | 203 | TupleType, |
|
224 | 226 | from mypy.types_utils import is_overlapping_none, remove_optional, store_argument_type, strip_type |
225 | 227 | from mypy.typetraverser import TypeTraverserVisitor |
226 | 228 | from mypy.typevars import fill_typevars, fill_typevars_with_any, has_no_typevars |
| 229 | +from mypy.type_visitor import TypeVisitor |
227 | 230 | from mypy.util import is_dunder, is_sunder |
228 | 231 | from mypy.visitor import NodeVisitor |
229 | 232 |
|
@@ -287,6 +290,83 @@ class PartialTypeScope(NamedTuple): |
287 | 290 | is_local: bool |
288 | 291 |
|
289 | 292 |
|
| 293 | +class InstanceDeprecatedVisitor(TypeVisitor[None]): |
| 294 | + """Visitor that recursively checks for deprecations in nested instances.""" |
| 295 | + |
| 296 | + def __init__(self, typechecker: TypeChecker, context: Context) -> None: |
| 297 | + self.typechecker = typechecker |
| 298 | + self.context = context |
| 299 | + |
| 300 | + def visit_any(self, t: AnyType) -> None: |
| 301 | + pass |
| 302 | + |
| 303 | + def visit_callable_type(self, t: CallableType) -> None: |
| 304 | + for arg_type in t.arg_types: |
| 305 | + arg_type.accept(self) |
| 306 | + t.ret_type.accept(self) |
| 307 | + |
| 308 | + def visit_deleted_type(self, t: DeletedType) -> None: |
| 309 | + pass |
| 310 | + |
| 311 | + def visit_erased_type(self, t: ErasedType) -> None: |
| 312 | + pass |
| 313 | + |
| 314 | + def visit_instance(self, t: Instance) -> None: |
| 315 | + self.typechecker.check_deprecated(t.type, self.context) |
| 316 | + for arg in t.args: |
| 317 | + arg.accept(self) |
| 318 | + |
| 319 | + def visit_literal_type(self, t: LiteralType) -> None: |
| 320 | + pass |
| 321 | + |
| 322 | + def visit_none_type(self, t: NoneType) -> None: |
| 323 | + pass |
| 324 | + |
| 325 | + def visit_overloaded(self, t: Overloaded) -> None: |
| 326 | + pass |
| 327 | + |
| 328 | + def visit_param_spec(self, t: ParamSpecType) -> None: |
| 329 | + pass |
| 330 | + |
| 331 | + def visit_parameters(self, t: Parameters) -> None: |
| 332 | + pass |
| 333 | + |
| 334 | + def visit_partial_type(self, t: PartialType) -> None: |
| 335 | + pass |
| 336 | + |
| 337 | + def visit_tuple_type(self, t: TupleType) -> None: |
| 338 | + for item in t.items: |
| 339 | + item.accept(self) |
| 340 | + |
| 341 | + def visit_type_alias_type(self, t: TypeAliasType) -> None: |
| 342 | + t.alias.target.accept(self) |
| 343 | + |
| 344 | + def visit_type_type(self, t: TypeType) -> None: |
| 345 | + pass |
| 346 | + |
| 347 | + def visit_type_var(self, t: TypeVarType) -> None: |
| 348 | + pass |
| 349 | + |
| 350 | + def visit_type_var_tuple(self, t: TypeVarTupleType) -> None: |
| 351 | + pass |
| 352 | + |
| 353 | + def visit_typeddict_type(self, t: TypedDictType) -> None: |
| 354 | + pass |
| 355 | + |
| 356 | + def visit_unbound_type(self, t: UnboundType) -> None: |
| 357 | + pass |
| 358 | + |
| 359 | + def visit_uninhabited_type(self, t: UninhabitedType) -> None: |
| 360 | + pass |
| 361 | + |
| 362 | + def visit_union_type(self, t: UnionType) -> None: |
| 363 | + for item in t.items: |
| 364 | + item.accept(self) |
| 365 | + |
| 366 | + def visit_unpack_type(self, t: UnpackType) -> None: |
| 367 | + pass |
| 368 | + |
| 369 | + |
290 | 370 | class TypeChecker(NodeVisitor[None], CheckerPluginInterface): |
291 | 371 | """Mypy type checker. |
292 | 372 |
|
@@ -2932,8 +3012,12 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: |
2932 | 3012 |
|
2933 | 3013 | if s.unanalyzed_type is not None: |
2934 | 3014 | for lvalue in s.lvalues: |
2935 | | - if isinstance(lvalue, NameExpr) and isinstance(var := lvalue.node, Var): |
2936 | | - self.search_deprecated(var.type, s, set()) |
| 3015 | + if ( |
| 3016 | + isinstance(lvalue, NameExpr) |
| 3017 | + and isinstance(var := lvalue.node, Var) |
| 3018 | + and (var.type is not None) |
| 3019 | + ): |
| 3020 | + var.type.accept(InstanceDeprecatedVisitor(typechecker=self, context=s)) |
2937 | 3021 |
|
2938 | 3022 | # Avoid type checking type aliases in stubs to avoid false |
2939 | 3023 | # positives about modern type syntax available in stubs such |
@@ -7577,20 +7661,6 @@ def warn_deprecated(self, node: SymbolNode | None, context: Context) -> None: |
7577 | 7661 | warn = self.msg.fail if self.options.report_deprecated_as_error else self.msg.note |
7578 | 7662 | warn(deprecated, context, code=codes.DEPRECATED) |
7579 | 7663 |
|
7580 | | - def search_deprecated( |
7581 | | - self, typ: Type | None, s: AssignmentStmt, visited: set[Type | None] |
7582 | | - ) -> None: |
7583 | | - |
7584 | | - if typ not in visited: |
7585 | | - visited.add(typ) |
7586 | | - if isinstance(typ := get_proper_type(typ), Instance): |
7587 | | - self.check_deprecated(typ.type, s) |
7588 | | - for arg in typ.args: |
7589 | | - self.search_deprecated(arg, s, visited) |
7590 | | - elif isinstance(typ, (UnionType, TupleType)): |
7591 | | - for item in typ.items: |
7592 | | - self.search_deprecated(item, s, visited) |
7593 | | - |
7594 | 7664 |
|
7595 | 7665 | class CollectArgTypeVarTypes(TypeTraverserVisitor): |
7596 | 7666 | """Collects the non-nested argument types in a set.""" |
|
0 commit comments