Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,13 @@ def __init__(
self._expr_checker = mypy.checkexpr.ExpressionChecker(
self, self.msg, self.plugin, per_line_checking_time_ns
)

self._str_type: Instance | None = None
self._function_type: Instance | None = None
self._int_type: Instance | None = None
self._bool_type: Instance | None = None
self._object_type: Instance | None = None

self.pattern_checker = PatternChecker(self, self.msg, self.plugin, options)
self._unique_id = 0

Expand Down Expand Up @@ -7369,6 +7376,29 @@ def named_type(self, name: str) -> Instance:

For example, named_type('builtins.object') produces the 'object' type.
"""
if name == "builtins.str":
if self._str_type is None:
self._str_type = self._named_type(name)
return self._str_type
if name == "builtins.function":
if self._function_type is None:
self._function_type = self._named_type(name)
return self._function_type
if name == "builtins.int":
if self._int_type is None:
self._int_type = self._named_type(name)
return self._int_type
if name == "builtins.bool":
if self._bool_type is None:
self._bool_type = self._named_type(name)
return self._bool_type
if name == "builtins.object":
if self._object_type is None:
self._object_type = self._named_type(name)
return self._object_type
return self._named_type(name)

def _named_type(self, name: str) -> Instance:
# Assume that the name refers to a type.
sym = self.lookup_qualified(name)
node = sym.node
Expand Down
21 changes: 16 additions & 5 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@ def __init__(
] = {}
self.in_lambda_expr = False

self._literal_true: Instance | None = None
self._literal_false: Instance | None = None

def reset(self) -> None:
self.resolved_type = {}
self.expr_cache.clear()
Expand Down Expand Up @@ -3428,11 +3431,19 @@ def infer_literal_expr_type(self, value: LiteralValue, fallback_name: str) -> Ty
if self.is_literal_context():
return LiteralType(value=value, fallback=typ)
else:
return typ.copy_modified(
last_known_value=LiteralType(
value=value, fallback=typ, line=typ.line, column=typ.column
)
)
if value is True:
if self._literal_true is None:
self._literal_true = typ.copy_modified(
last_known_value=LiteralType(value=value, fallback=typ)
)
return self._literal_true
if value is False:
if self._literal_false is None:
self._literal_false = typ.copy_modified(
last_known_value=LiteralType(value=value, fallback=typ)
)
return self._literal_false
return typ.copy_modified(last_known_value=LiteralType(value=value, fallback=typ))

def concat_tuples(self, left: TupleType, right: TupleType) -> TupleType:
"""Concatenate two fixed length tuples."""
Expand Down
25 changes: 18 additions & 7 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,10 @@ def __init__(
# Used to track edge case when return is still inside except* if it enters a loop
self.return_stmt_inside_except_star_block: bool = False

self._str_type: Instance | None = None
self._function_type: Instance | None = None
self._object_type: Instance | None = None

# mypyc doesn't properly handle implementing an abstractproperty
# with a regular attribute so we make them properties
@property
Expand Down Expand Up @@ -1241,7 +1245,7 @@ def analyze_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
# This is a property.
first_item.func.is_overload = True
bare_setter_type = self.analyze_property_with_multi_part_definition(defn)
typ = function_type(first_item.func, self.named_type("builtins.function"))
typ = function_type(first_item.func, self.function_type())
assert isinstance(typ, CallableType)
typ.definition = first_item
types = [typ]
Expand Down Expand Up @@ -1373,7 +1377,7 @@ def analyze_overload_sigs_and_impl(
item.accept(self)
# TODO: support decorated overloaded functions properly
if isinstance(item, Decorator):
callable = function_type(item.func, self.named_type("builtins.function"))
callable = function_type(item.func, self.function_type())
assert isinstance(callable, CallableType)
callable.definition = item
if not any(refers_to_fullname(dec, OVERLOAD_NAMES) for dec in item.decorators):
Expand Down Expand Up @@ -1536,9 +1540,7 @@ def analyze_property_with_multi_part_definition(
if first_node.name == "setter":
# The first item represents the entire property.
first_item.var.is_settable_property = True
setter_func_type = function_type(
item.func, self.named_type("builtins.function")
)
setter_func_type = function_type(item.func, self.function_type())
assert isinstance(setter_func_type, CallableType)
bare_setter_type = setter_func_type
defn.setter_index = i + 1
Expand Down Expand Up @@ -6630,10 +6632,19 @@ def lookup_fully_qualified_or_none(self, fullname: str) -> SymbolTableNode | Non
return result

def object_type(self) -> Instance:
return self.named_type("builtins.object")
if self._object_type is None:
self._object_type = self.named_type("builtins.object")
return self._object_type

def str_type(self) -> Instance:
return self.named_type("builtins.str")
if self._str_type is None:
self._str_type = self.named_type("builtins.str")
return self._str_type

def function_type(self) -> Instance:
if self._function_type is None:
self._function_type = self.named_type("builtins.function")
return self._function_type

def named_type(self, fullname: str, args: list[Type] | None = None) -> Instance:
sym = self.lookup_fully_qualified(fullname)
Expand Down
Loading