|
32 | 32 | from typing_extensions import get_origin, is_typeddict |
33 | 33 |
|
34 | 34 | import mypy.build |
| 35 | +import mypy.checkexpr |
| 36 | +import mypy.checkmember |
| 37 | +import mypy.erasetype |
35 | 38 | import mypy.modulefinder |
36 | 39 | import mypy.nodes |
37 | 40 | import mypy.state |
@@ -670,7 +673,11 @@ def _verify_arg_default_value( |
670 | 673 | "has a default value but stub argument does not" |
671 | 674 | ) |
672 | 675 | else: |
673 | | - runtime_type = get_mypy_type_of_runtime_value(runtime_arg.default) |
| 676 | + type_context = stub_arg.variable.type |
| 677 | + runtime_type = get_mypy_type_of_runtime_value( |
| 678 | + runtime_arg.default, type_context=type_context |
| 679 | + ) |
| 680 | + |
674 | 681 | # Fallback to the type annotation type if var type is missing. The type annotation |
675 | 682 | # is an UnboundType, but I don't know enough to know what the pros and cons here are. |
676 | 683 | # UnboundTypes have ugly question marks following them, so default to var type. |
@@ -1097,7 +1104,7 @@ def verify_var( |
1097 | 1104 | ): |
1098 | 1105 | yield Error(object_path, "is read-only at runtime but not in the stub", stub, runtime) |
1099 | 1106 |
|
1100 | | - runtime_type = get_mypy_type_of_runtime_value(runtime) |
| 1107 | + runtime_type = get_mypy_type_of_runtime_value(runtime, type_context=stub.type) |
1101 | 1108 | if ( |
1102 | 1109 | runtime_type is not None |
1103 | 1110 | and stub.type is not None |
@@ -1586,7 +1593,9 @@ def is_subtype_helper(left: mypy.types.Type, right: mypy.types.Type) -> bool: |
1586 | 1593 | return mypy.subtypes.is_subtype(left, right) |
1587 | 1594 |
|
1588 | 1595 |
|
1589 | | -def get_mypy_type_of_runtime_value(runtime: Any) -> mypy.types.Type | None: |
| 1596 | +def get_mypy_type_of_runtime_value( |
| 1597 | + runtime: Any, type_context: mypy.types.Type | None = None |
| 1598 | +) -> mypy.types.Type | None: |
1590 | 1599 | """Returns a mypy type object representing the type of ``runtime``. |
1591 | 1600 |
|
1592 | 1601 | Returns None if we can't find something that works. |
@@ -1647,7 +1656,49 @@ def anytype() -> mypy.types.AnyType: |
1647 | 1656 | is_ellipsis_args=True, |
1648 | 1657 | ) |
1649 | 1658 |
|
1650 | | - # Try and look up a stub for the runtime object |
| 1659 | + if type_context: |
| 1660 | + # Don't attempt to account for context if the context is generic |
| 1661 | + # This is related to issue #3737 |
| 1662 | + if isinstance(type_context, mypy.types.CallableType): |
| 1663 | + if isinstance(type_context.ret_type, mypy.types.TypeVarType): |
| 1664 | + type_context = None |
| 1665 | + if isinstance(type_context, mypy.types.TypeType): |
| 1666 | + if isinstance(type_context.item, mypy.types.TypeVarType): |
| 1667 | + type_context = None |
| 1668 | + |
| 1669 | + if type_context: |
| 1670 | + |
| 1671 | + def _named_type(name: str) -> mypy.types.Instance: |
| 1672 | + parts = name.rsplit(".", maxsplit=1) |
| 1673 | + stub = get_stub(parts[0]) |
| 1674 | + if stub is not None: |
| 1675 | + if parts[1] in stub.names: |
| 1676 | + node = stub.names[parts[1]] |
| 1677 | + assert isinstance(node.node, nodes.TypeInfo) |
| 1678 | + any_type = mypy.types.AnyType(mypy.types.TypeOfAny.special_form) |
| 1679 | + return mypy.types.Instance( |
| 1680 | + node.node, [any_type] * len(node.node.defn.type_vars) |
| 1681 | + ) |
| 1682 | + |
| 1683 | + any_type = mypy.types.AnyType(mypy.types.TypeOfAny.from_error) |
| 1684 | + return mypy.types.Instance(node.node, []) |
| 1685 | + |
| 1686 | + if isinstance(runtime, type): |
| 1687 | + # Try and look up a stub for the runtime object itself |
| 1688 | + # The logic here is similar to ExpressionChecker.analyze_ref_expr |
| 1689 | + stub = get_stub(runtime.__module__) |
| 1690 | + if stub is not None: |
| 1691 | + if runtime.__name__ in stub.names: |
| 1692 | + type_info = stub.names[runtime.__name__].node |
| 1693 | + if isinstance(type_info, nodes.TypeInfo): |
| 1694 | + result = mypy.checkmember.type_object_type(type_info, _named_type) |
| 1695 | + if mypy.checkexpr.is_type_type_context(type_context): |
| 1696 | + # This is the type in a type[] expression, so substitute type |
| 1697 | + # variables with Any. |
| 1698 | + result = mypy.erasetype.erase_typevars(result) |
| 1699 | + return result |
| 1700 | + |
| 1701 | + # Try and look up a stub for the runtime object's type |
1651 | 1702 | stub = get_stub(type(runtime).__module__) |
1652 | 1703 | if stub is None: |
1653 | 1704 | return None |
|
0 commit comments