semanal_infer.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. """Simple type inference for decorated functions during semantic analysis."""
  2. from __future__ import annotations
  3. from mypy.nodes import ARG_POS, CallExpr, Decorator, Expression, FuncDef, RefExpr, Var
  4. from mypy.semanal_shared import SemanticAnalyzerInterface
  5. from mypy.typeops import function_type
  6. from mypy.types import (
  7. AnyType,
  8. CallableType,
  9. ProperType,
  10. Type,
  11. TypeOfAny,
  12. TypeVarType,
  13. get_proper_type,
  14. )
  15. from mypy.typevars import has_no_typevars
  16. def infer_decorator_signature_if_simple(
  17. dec: Decorator, analyzer: SemanticAnalyzerInterface
  18. ) -> None:
  19. """Try to infer the type of the decorated function.
  20. This lets us resolve additional references to decorated functions
  21. during type checking. Otherwise the type might not be available
  22. when we need it, since module top levels can't be deferred.
  23. This basically uses a simple special-purpose type inference
  24. engine just for decorators.
  25. """
  26. if dec.var.is_property:
  27. # Decorators are expected to have a callable type (it's a little odd).
  28. if dec.func.type is None:
  29. dec.var.type = CallableType(
  30. [AnyType(TypeOfAny.special_form)],
  31. [ARG_POS],
  32. [None],
  33. AnyType(TypeOfAny.special_form),
  34. analyzer.named_type("builtins.function"),
  35. name=dec.var.name,
  36. )
  37. elif isinstance(dec.func.type, CallableType):
  38. dec.var.type = dec.func.type
  39. return
  40. decorator_preserves_type = True
  41. for expr in dec.decorators:
  42. preserve_type = False
  43. if isinstance(expr, RefExpr) and isinstance(expr.node, FuncDef):
  44. if expr.node.type and is_identity_signature(expr.node.type):
  45. preserve_type = True
  46. if not preserve_type:
  47. decorator_preserves_type = False
  48. break
  49. if decorator_preserves_type:
  50. # No non-identity decorators left. We can trivially infer the type
  51. # of the function here.
  52. dec.var.type = function_type(dec.func, analyzer.named_type("builtins.function"))
  53. if dec.decorators:
  54. return_type = calculate_return_type(dec.decorators[0])
  55. if return_type and isinstance(return_type, AnyType):
  56. # The outermost decorator will return Any so we know the type of the
  57. # decorated function.
  58. dec.var.type = AnyType(TypeOfAny.from_another_any, source_any=return_type)
  59. sig = find_fixed_callable_return(dec.decorators[0])
  60. if sig:
  61. # The outermost decorator always returns the same kind of function,
  62. # so we know that this is the type of the decorated function.
  63. orig_sig = function_type(dec.func, analyzer.named_type("builtins.function"))
  64. sig.name = orig_sig.items[0].name
  65. dec.var.type = sig
  66. def is_identity_signature(sig: Type) -> bool:
  67. """Is type a callable of form T -> T (where T is a type variable)?"""
  68. sig = get_proper_type(sig)
  69. if isinstance(sig, CallableType) and sig.arg_kinds == [ARG_POS]:
  70. if isinstance(sig.arg_types[0], TypeVarType) and isinstance(sig.ret_type, TypeVarType):
  71. return sig.arg_types[0].id == sig.ret_type.id
  72. return False
  73. def calculate_return_type(expr: Expression) -> ProperType | None:
  74. """Return the return type if we can calculate it.
  75. This only uses information available during semantic analysis so this
  76. will sometimes return None because of insufficient information (as
  77. type inference hasn't run yet).
  78. """
  79. if isinstance(expr, RefExpr):
  80. if isinstance(expr.node, FuncDef):
  81. typ = expr.node.type
  82. if typ is None:
  83. # No signature -> default to Any.
  84. return AnyType(TypeOfAny.unannotated)
  85. # Explicit Any return?
  86. if isinstance(typ, CallableType):
  87. return get_proper_type(typ.ret_type)
  88. return None
  89. elif isinstance(expr.node, Var):
  90. return get_proper_type(expr.node.type)
  91. elif isinstance(expr, CallExpr):
  92. return calculate_return_type(expr.callee)
  93. return None
  94. def find_fixed_callable_return(expr: Expression) -> CallableType | None:
  95. """Return the return type, if expression refers to a callable that returns a callable.
  96. But only do this if the return type has no type variables. Return None otherwise.
  97. This approximates things a lot as this is supposed to be called before type checking
  98. when full type information is not available yet.
  99. """
  100. if isinstance(expr, RefExpr):
  101. if isinstance(expr.node, FuncDef):
  102. typ = expr.node.type
  103. if typ:
  104. if isinstance(typ, CallableType) and has_no_typevars(typ.ret_type):
  105. ret_type = get_proper_type(typ.ret_type)
  106. if isinstance(ret_type, CallableType):
  107. return ret_type
  108. elif isinstance(expr, CallExpr):
  109. t = find_fixed_callable_return(expr.callee)
  110. if t:
  111. ret_type = get_proper_type(t.ret_type)
  112. if isinstance(ret_type, CallableType):
  113. return ret_type
  114. return None