Skip to content

Commit 968a8bd

Browse files
committed
Merge remote-tracking branch 'upstream/master' into bugfix/st-synthetic-named-expr-in-match
2 parents 5e0b259 + 4f284a3 commit 968a8bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1457
-754
lines changed

mypy/argmap.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,8 @@ def expand_actual_type(
249249
formal_name = (set(actual_type.items.keys()) - self.kwargs_used).pop()
250250
self.kwargs_used.add(formal_name)
251251
return actual_type.items[formal_name]
252-
elif (
253-
isinstance(actual_type, Instance)
254-
and len(actual_type.args) > 1
255-
and is_subtype(actual_type, self.context.mapping_type)
252+
elif isinstance(actual_type, Instance) and is_subtype(
253+
actual_type, self.context.mapping_type
256254
):
257255
# Only `Mapping` type can be unpacked with `**`.
258256
# Other types will produce an error somewhere else.

mypy/checker.py

+213-403
Large diffs are not rendered by default.

mypy/checker_shared.py

+349
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
"""Shared definitions used by different parts of type checker."""
2+
3+
from __future__ import annotations
4+
5+
from abc import abstractmethod
6+
from collections.abc import Iterator, Sequence
7+
from contextlib import contextmanager
8+
from typing import NamedTuple, overload
9+
10+
from mypy_extensions import trait
11+
12+
from mypy.errorcodes import ErrorCode
13+
from mypy.errors import ErrorWatcher
14+
from mypy.message_registry import ErrorMessage
15+
from mypy.nodes import (
16+
ArgKind,
17+
Context,
18+
Expression,
19+
FuncItem,
20+
LambdaExpr,
21+
MypyFile,
22+
Node,
23+
RefExpr,
24+
TypeAlias,
25+
TypeInfo,
26+
Var,
27+
)
28+
from mypy.plugin import CheckerPluginInterface, Plugin
29+
from mypy.types import (
30+
CallableType,
31+
Instance,
32+
LiteralValue,
33+
Overloaded,
34+
PartialType,
35+
TupleType,
36+
Type,
37+
TypedDictType,
38+
TypeType,
39+
)
40+
from mypy.typevars import fill_typevars
41+
42+
43+
# An object that represents either a precise type or a type with an upper bound;
44+
# it is important for correct type inference with isinstance.
45+
class TypeRange(NamedTuple):
46+
item: Type
47+
is_upper_bound: bool # False => precise type
48+
49+
50+
@trait
51+
class ExpressionCheckerSharedApi:
52+
@abstractmethod
53+
def accept(
54+
self,
55+
node: Expression,
56+
type_context: Type | None = None,
57+
allow_none_return: bool = False,
58+
always_allow_any: bool = False,
59+
is_callee: bool = False,
60+
) -> Type:
61+
raise NotImplementedError
62+
63+
@abstractmethod
64+
def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type:
65+
raise NotImplementedError
66+
67+
@abstractmethod
68+
def module_type(self, node: MypyFile) -> Instance:
69+
raise NotImplementedError
70+
71+
@abstractmethod
72+
def check_call(
73+
self,
74+
callee: Type,
75+
args: list[Expression],
76+
arg_kinds: list[ArgKind],
77+
context: Context,
78+
arg_names: Sequence[str | None] | None = None,
79+
callable_node: Expression | None = None,
80+
callable_name: str | None = None,
81+
object_type: Type | None = None,
82+
original_type: Type | None = None,
83+
) -> tuple[Type, Type]:
84+
raise NotImplementedError
85+
86+
@abstractmethod
87+
def transform_callee_type(
88+
self,
89+
callable_name: str | None,
90+
callee: Type,
91+
args: list[Expression],
92+
arg_kinds: list[ArgKind],
93+
context: Context,
94+
arg_names: Sequence[str | None] | None = None,
95+
object_type: Type | None = None,
96+
) -> Type:
97+
raise NotImplementedError
98+
99+
@abstractmethod
100+
def method_fullname(self, object_type: Type, method_name: str) -> str | None:
101+
raise NotImplementedError
102+
103+
@abstractmethod
104+
def check_method_call_by_name(
105+
self,
106+
method: str,
107+
base_type: Type,
108+
args: list[Expression],
109+
arg_kinds: list[ArgKind],
110+
context: Context,
111+
original_type: Type | None = None,
112+
) -> tuple[Type, Type]:
113+
raise NotImplementedError
114+
115+
@abstractmethod
116+
def alias_type_in_runtime_context(
117+
self, alias: TypeAlias, *, ctx: Context, alias_definition: bool = False
118+
) -> Type:
119+
raise NotImplementedError
120+
121+
@abstractmethod
122+
def visit_typeddict_index_expr(
123+
self, td_type: TypedDictType, index: Expression, setitem: bool = False
124+
) -> tuple[Type, set[str]]:
125+
raise NotImplementedError
126+
127+
@abstractmethod
128+
def typeddict_callable(self, info: TypeInfo) -> CallableType:
129+
raise NotImplementedError
130+
131+
@abstractmethod
132+
def infer_literal_expr_type(self, value: LiteralValue, fallback_name: str) -> Type:
133+
raise NotImplementedError
134+
135+
136+
@trait
137+
class TypeCheckerSharedApi(CheckerPluginInterface):
138+
plugin: Plugin
139+
module_refs: set[str]
140+
scope: CheckerScope
141+
checking_missing_await: bool
142+
143+
@property
144+
@abstractmethod
145+
def expr_checker(self) -> ExpressionCheckerSharedApi:
146+
raise NotImplementedError
147+
148+
@abstractmethod
149+
def named_type(self, name: str) -> Instance:
150+
raise NotImplementedError
151+
152+
@abstractmethod
153+
def lookup_typeinfo(self, fullname: str) -> TypeInfo:
154+
raise NotImplementedError
155+
156+
@abstractmethod
157+
def lookup_type(self, node: Expression) -> Type:
158+
raise NotImplementedError
159+
160+
@abstractmethod
161+
def handle_cannot_determine_type(self, name: str, context: Context) -> None:
162+
raise NotImplementedError
163+
164+
@abstractmethod
165+
def handle_partial_var_type(
166+
self, typ: PartialType, is_lvalue: bool, node: Var, context: Context
167+
) -> Type:
168+
raise NotImplementedError
169+
170+
@overload
171+
@abstractmethod
172+
def check_subtype(
173+
self,
174+
subtype: Type,
175+
supertype: Type,
176+
context: Context,
177+
msg: str,
178+
subtype_label: str | None = None,
179+
supertype_label: str | None = None,
180+
*,
181+
notes: list[str] | None = None,
182+
code: ErrorCode | None = None,
183+
outer_context: Context | None = None,
184+
) -> bool: ...
185+
186+
@overload
187+
@abstractmethod
188+
def check_subtype(
189+
self,
190+
subtype: Type,
191+
supertype: Type,
192+
context: Context,
193+
msg: ErrorMessage,
194+
subtype_label: str | None = None,
195+
supertype_label: str | None = None,
196+
*,
197+
notes: list[str] | None = None,
198+
outer_context: Context | None = None,
199+
) -> bool: ...
200+
201+
# Unfortunately, mypyc doesn't support abstract overloads yet.
202+
@abstractmethod
203+
def check_subtype(
204+
self,
205+
subtype: Type,
206+
supertype: Type,
207+
context: Context,
208+
msg: str | ErrorMessage,
209+
subtype_label: str | None = None,
210+
supertype_label: str | None = None,
211+
*,
212+
notes: list[str] | None = None,
213+
code: ErrorCode | None = None,
214+
outer_context: Context | None = None,
215+
) -> bool:
216+
raise NotImplementedError
217+
218+
@abstractmethod
219+
def get_final_context(self) -> bool:
220+
raise NotImplementedError
221+
222+
@overload
223+
@abstractmethod
224+
def conditional_types_with_intersection(
225+
self,
226+
expr_type: Type,
227+
type_ranges: list[TypeRange] | None,
228+
ctx: Context,
229+
default: None = None,
230+
) -> tuple[Type | None, Type | None]: ...
231+
232+
@overload
233+
@abstractmethod
234+
def conditional_types_with_intersection(
235+
self, expr_type: Type, type_ranges: list[TypeRange] | None, ctx: Context, default: Type
236+
) -> tuple[Type, Type]: ...
237+
238+
# Unfortunately, mypyc doesn't support abstract overloads yet.
239+
@abstractmethod
240+
def conditional_types_with_intersection(
241+
self,
242+
expr_type: Type,
243+
type_ranges: list[TypeRange] | None,
244+
ctx: Context,
245+
default: Type | None = None,
246+
) -> tuple[Type | None, Type | None]:
247+
raise NotImplementedError
248+
249+
@abstractmethod
250+
def check_deprecated(self, node: Node | None, context: Context) -> None:
251+
raise NotImplementedError
252+
253+
@abstractmethod
254+
def warn_deprecated(self, node: Node | None, context: Context) -> None:
255+
raise NotImplementedError
256+
257+
@abstractmethod
258+
def warn_deprecated_overload_item(
259+
self, node: Node | None, context: Context, *, target: Type, selftype: Type | None = None
260+
) -> None:
261+
raise NotImplementedError
262+
263+
@abstractmethod
264+
def type_is_iterable(self, type: Type) -> bool:
265+
raise NotImplementedError
266+
267+
@abstractmethod
268+
def iterable_item_type(
269+
self, it: Instance | CallableType | TypeType | Overloaded, context: Context
270+
) -> Type:
271+
raise NotImplementedError
272+
273+
@abstractmethod
274+
@contextmanager
275+
def checking_await_set(self) -> Iterator[None]:
276+
raise NotImplementedError
277+
278+
@abstractmethod
279+
def get_precise_awaitable_type(self, typ: Type, local_errors: ErrorWatcher) -> Type | None:
280+
raise NotImplementedError
281+
282+
283+
class CheckerScope:
284+
# We keep two stacks combined, to maintain the relative order
285+
stack: list[TypeInfo | FuncItem | MypyFile]
286+
287+
def __init__(self, module: MypyFile) -> None:
288+
self.stack = [module]
289+
290+
def current_function(self) -> FuncItem | None:
291+
for e in reversed(self.stack):
292+
if isinstance(e, FuncItem):
293+
return e
294+
return None
295+
296+
def top_level_function(self) -> FuncItem | None:
297+
"""Return top-level non-lambda function."""
298+
for e in self.stack:
299+
if isinstance(e, FuncItem) and not isinstance(e, LambdaExpr):
300+
return e
301+
return None
302+
303+
def active_class(self) -> TypeInfo | None:
304+
if isinstance(self.stack[-1], TypeInfo):
305+
return self.stack[-1]
306+
return None
307+
308+
def enclosing_class(self, func: FuncItem | None = None) -> TypeInfo | None:
309+
"""Is there a class *directly* enclosing this function?"""
310+
func = func or self.current_function()
311+
assert func, "This method must be called from inside a function"
312+
index = self.stack.index(func)
313+
assert index, "CheckerScope stack must always start with a module"
314+
enclosing = self.stack[index - 1]
315+
if isinstance(enclosing, TypeInfo):
316+
return enclosing
317+
return None
318+
319+
def active_self_type(self) -> Instance | TupleType | None:
320+
"""An instance or tuple type representing the current class.
321+
322+
This returns None unless we are in class body or in a method.
323+
In particular, inside a function nested in method this returns None.
324+
"""
325+
info = self.active_class()
326+
if not info and self.current_function():
327+
info = self.enclosing_class()
328+
if info:
329+
return fill_typevars(info)
330+
return None
331+
332+
def current_self_type(self) -> Instance | TupleType | None:
333+
"""Same as active_self_type() but handle functions nested in methods."""
334+
for item in reversed(self.stack):
335+
if isinstance(item, TypeInfo):
336+
return fill_typevars(item)
337+
return None
338+
339+
@contextmanager
340+
def push_function(self, item: FuncItem) -> Iterator[None]:
341+
self.stack.append(item)
342+
yield
343+
self.stack.pop()
344+
345+
@contextmanager
346+
def push_class(self, info: TypeInfo) -> Iterator[None]:
347+
self.stack.append(info)
348+
yield
349+
self.stack.pop()

0 commit comments

Comments
 (0)