Skip to content

Commit 517beb1

Browse files
authored
Merge branch 'master' into fix/mypyc-defaults-setup-cache-load
2 parents c6cae72 + 4c8f994 commit 517beb1

26 files changed

Lines changed: 530 additions & 87 deletions

CHANGELOG.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Contributed by Jukka Lehtosalo (PR [21433](https://github.com/python/mypy/pull/2
3838

3939
### Mypyc Improvements
4040

41+
- Enable incremental self-compilation (Vaggelis Danias, PR [21369](https://github.com/python/mypy/pull/21369))
4142
- Make compilation order with multiple files consistent (Piotr Sawicki, PR [21419](https://github.com/python/mypy/pull/21419))
4243
- Fix crash on accessing `StopAsyncIteration` (Piotr Sawicki, PR [21406](https://github.com/python/mypy/pull/21406))
4344
- Fix incremental compilation with `separate` flag (Vaggelis Danias, PR [21299](https://github.com/python/mypy/pull/21299))
@@ -54,15 +55,13 @@ Contributed by Jukka Lehtosalo (PR [21433](https://github.com/python/mypy/pull/2
5455
### Other Notable Fixes and Improvements
5556

5657
- Rely on typeshed stubs for `slice` typing (Ivan Levkivskyi, PR [21401](https://github.com/python/mypy/pull/21401))
57-
- Improve negative narrowing for membership checks on tuples (Shantanu, PR [21456](https://github.com/python/mypy/pull/21456))
5858
- Narrow match captures based on previous cases (Shantanu, PR [21405](https://github.com/python/mypy/pull/21405))
5959
- Fix nondeterminism in overload resolution (Shantanu, PR [21455](https://github.com/python/mypy/pull/21455))
6060
- Respect file config comments for stale modules (Adam Turner, PR [21444](https://github.com/python/mypy/pull/21444))
6161
- Fix JSON output mode for syntax errors in parallel mode (Adam Turner, PR [21434](https://github.com/python/mypy/pull/21434))
6262
- Fix type variable with values as a supertype (Ivan Levkivskyi, PR [21431](https://github.com/python/mypy/pull/21431))
6363
- Add support for configuring `--num-workers` with an environment variable (Kevin Kannammalil, PR [21407](https://github.com/python/mypy/pull/21407))
6464
- Respect JSON output mode for syntax errors (Adam Turner, PR [21386](https://github.com/python/mypy/pull/21386))
65-
- Analyze `TypedDict` decorators (Pranav Manglik, PR [21267](https://github.com/python/mypy/pull/21267))
6665

6766
### Typeshed Updates
6867

mypy/checkexpr.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,12 +1948,7 @@ def analyze_type_type_callee(self, item: ProperType, context: Context) -> Type:
19481948
# but better than AnyType...), but replace the return type
19491949
# with typevar.
19501950
callee = self.analyze_type_type_callee(get_proper_type(item.upper_bound), context)
1951-
callee = get_proper_type(callee)
1952-
if isinstance(callee, CallableType):
1953-
callee = callee.copy_modified(ret_type=item)
1954-
elif isinstance(callee, Overloaded):
1955-
callee = Overloaded([c.copy_modified(ret_type=item) for c in callee.items])
1956-
return callee
1951+
return self.replace_type_type_callee_ret_type(callee, item)
19571952
# We support Type of namedtuples but not of tuples in general
19581953
if isinstance(item, TupleType) and tuple_fallback(item).type.fullname != "builtins.tuple":
19591954
return self.analyze_type_type_callee(tuple_fallback(item), context)
@@ -1963,6 +1958,23 @@ def analyze_type_type_callee(self, item: ProperType, context: Context) -> Type:
19631958
self.msg.unsupported_type_type(item, context)
19641959
return AnyType(TypeOfAny.from_error)
19651960

1961+
def replace_type_type_callee_ret_type(self, callee: Type, ret_type: Type) -> Type:
1962+
callee = get_proper_type(callee)
1963+
if isinstance(callee, CallableType):
1964+
return callee.copy_modified(ret_type=ret_type)
1965+
if isinstance(callee, Overloaded):
1966+
return Overloaded([c.copy_modified(ret_type=ret_type) for c in callee.items])
1967+
if isinstance(callee, UnionType):
1968+
return UnionType(
1969+
[
1970+
self.replace_type_type_callee_ret_type(item, ret_type)
1971+
for item in callee.relevant_items()
1972+
],
1973+
line=callee.line,
1974+
column=callee.column,
1975+
)
1976+
return callee
1977+
19661978
def infer_arg_types_in_empty_context(self, args: list[Expression]) -> list[Type]:
19671979
"""Infer argument expression types in an empty context.
19681980

mypy/meet.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,28 @@ def visit_tuple_type(self, t: TupleType) -> ProperType:
10901090
elif isinstance(self.s, Instance):
10911091
# meet(Tuple[t1, t2, <...>], Tuple[s, ...]) == Tuple[meet(t1, s), meet(t2, s), <...>].
10921092
if self.s.type.fullname in TUPLE_LIKE_INSTANCE_NAMES and self.s.args:
1093-
return t.copy_modified(items=[meet_types(it, self.s.args[0]) for it in t.items])
1093+
arg = self.s.args[0]
1094+
new_items: list[Type] = []
1095+
for it in t.items:
1096+
# Unpack items need to be handled by the caller.
1097+
if isinstance(it, UnpackType):
1098+
unpacked = get_proper_type(it.type)
1099+
if isinstance(unpacked, TypeVarTupleType):
1100+
# We can't infer anything in this case.
1101+
new_arg = UninhabitedType()
1102+
instance = unpacked.tuple_fallback
1103+
else:
1104+
assert (
1105+
isinstance(unpacked, Instance)
1106+
and unpacked.type.fullname == "builtins.tuple"
1107+
)
1108+
new_arg = meet_types(unpacked.args[0], arg)
1109+
instance = unpacked
1110+
new_items.append(UnpackType(instance.copy_modified(args=[new_arg])))
1111+
else:
1112+
# All other items can be processed in a regular way.
1113+
new_items.append(meet_types(it, arg))
1114+
return t.copy_modified(items=new_items)
10941115
elif is_proper_subtype(t, self.s):
10951116
# A named tuple that inherits from a normal class
10961117
return t

mypy/message_registry.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ def with_additional_msg(self, info: str) -> ErrorMessage:
181181
'Implicit generic "Any". Use "{}" and specify generic parameters'
182182
)
183183
NO_CYCLIC_DEFAULT: Final = "Cyclic type variable defaults are not supported"
184+
NO_DEFAULT_AFTER_TYPEVAR_TUPLE: Final = "A type variable with default cannot follow TypeVarTuple"
184185
INVALID_UNPACK: Final = "{} cannot be unpacked (must be tuple or TypeVarTuple)"
185186
INVALID_UNPACK_POSITION: Final = "Unpack is only valid in a variadic position"
186187
INVALID_PARAM_SPEC_LOCATION: Final = "Invalid location for ParamSpec {}"

mypy/mixedtraverser.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
TypeApplication,
1717
TypedDictExpr,
1818
TypeFormExpr,
19+
TypeInfo,
1920
TypeVarExpr,
2021
Var,
2122
WithStmt,
@@ -41,15 +42,29 @@ def visit_func(self, o: FuncItem, /) -> None:
4142
self.visit_optional_type(o.type)
4243

4344
def visit_class_def(self, o: ClassDef, /) -> None:
44-
# TODO: Should we visit generated methods/variables as well, either here or in
45-
# TraverserVisitor?
4645
super().visit_class_def(o)
47-
info = o.info
48-
if info:
49-
for base in info.bases:
50-
base.accept(self)
51-
if info.special_alias:
52-
info.special_alias.accept(self)
46+
if o.info:
47+
self.process_type_info(o.info)
48+
49+
def process_type_info(self, info: TypeInfo) -> None:
50+
# TODO: Should we visit generated methods/variables as well?
51+
# We should for methods generated by us (see below). But it is less clear for
52+
# 3rd party plugin generated methods (since we don't want to emit errors there).
53+
for base in info.bases:
54+
base.accept(self)
55+
if info.special_alias:
56+
# We need to accept all types that are conceptually identical like special
57+
# alias target and corresponding tuple_type or typeddict_type, since those
58+
# may be copies, and not the same object.
59+
info.special_alias.accept(self)
60+
if info.tuple_type:
61+
info.tuple_type.accept(self)
62+
if info.typeddict_type:
63+
info.typeddict_type.accept(self)
64+
if info.is_named_tuple or info.is_newtype:
65+
for sym in info.names.values():
66+
if sym.plugin_generated and sym.node:
67+
sym.node.accept(self)
5368

5469
def visit_type_alias_expr(self, o: TypeAliasExpr, /) -> None:
5570
super().visit_type_alias_expr(o)
@@ -64,19 +79,20 @@ def visit_type_var_expr(self, o: TypeVarExpr, /) -> None:
6479

6580
def visit_typeddict_expr(self, o: TypedDictExpr, /) -> None:
6681
super().visit_typeddict_expr(o)
67-
self.visit_optional_type(o.info.typeddict_type)
82+
self.process_type_info(o.info)
6883

6984
def visit_namedtuple_expr(self, o: NamedTupleExpr, /) -> None:
7085
super().visit_namedtuple_expr(o)
71-
assert o.info.tuple_type
72-
o.info.tuple_type.accept(self)
86+
self.process_type_info(o.info)
7387

7488
def visit__promote_expr(self, o: PromoteExpr, /) -> None:
7589
super().visit__promote_expr(o)
7690
o.type.accept(self)
7791

7892
def visit_newtype_expr(self, o: NewTypeExpr, /) -> None:
7993
super().visit_newtype_expr(o)
94+
if o.info:
95+
self.process_type_info(o.info)
8096
self.visit_optional_type(o.old_type)
8197

8298
# Statements

mypy/semanal.py

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,13 @@ def __init__(
546546
# to create the set lazily.
547547
self.types_fixed: set[TypeInfo | TypeAlias] | None = None
548548

549+
# Stack of type variables that have been removed from current class because they
550+
# cannot be bound unambiguously. This can happen if a (regular) type variable
551+
# with a default follows a type variable tuple.
552+
self.removed_type_vars: list[list[TypeVarType]] = [[]]
553+
549554
# mypyc doesn't properly handle implementing an abstractproperty
550-
# with a regular attribute so we make them properties
555+
# with a regular attribute, so we make them properties
551556
@property
552557
def type(self) -> TypeInfo | None:
553558
return self._type
@@ -1151,7 +1156,8 @@ def prepare_method_signature(self, func: FuncDef, info: TypeInfo, has_self_type:
11511156
leading_type = fill_typevars(info)
11521157
if func.is_class or func.name == "__new__":
11531158
leading_type = self.class_type(leading_type)
1154-
func.type = replace_implicit_first_type(functype, leading_type)
1159+
if not has_placeholder(leading_type):
1160+
func.type = replace_implicit_first_type(functype, leading_type)
11551161
elif has_self_type and isinstance(func.unanalyzed_type, CallableType):
11561162
if not isinstance(get_proper_type(func.unanalyzed_type.arg_types[0]), AnyType):
11571163
if self.is_expected_self_type(
@@ -1836,8 +1842,9 @@ def visit_class_def(self, defn: ClassDef) -> None:
18361842
if self.push_type_args(defn.type_args, defn) is None:
18371843
self.mark_incomplete(defn.name, defn)
18381844
return
1839-
1845+
self.removed_type_vars.append([])
18401846
self.analyze_class(defn)
1847+
self.removed_type_vars.pop()
18411848
self.pop_type_args(defn.type_args)
18421849
self.incomplete_type_stack.pop()
18431850

@@ -2084,7 +2091,21 @@ def check_type_alias_bases(self, bases: list[Expression]) -> None:
20842091
)
20852092

20862093
def setup_type_vars(self, defn: ClassDef, tvar_defs: list[TypeVarLikeType]) -> None:
2087-
defn.type_vars = tvar_defs
2094+
seen_tvt = False
2095+
valid_tvar_defs = []
2096+
for tv in tvar_defs:
2097+
if seen_tvt and isinstance(tv, TypeVarType) and tv.has_default():
2098+
self.fail(
2099+
message_registry.NO_DEFAULT_AFTER_TYPEVAR_TUPLE, defn, code=codes.TYPE_VAR
2100+
)
2101+
# Remove the ambiguous type variable, and record it, so that we can replace
2102+
# all its uses with Any.
2103+
self.removed_type_vars[-1].append(tv)
2104+
continue
2105+
if isinstance(tv, TypeVarTupleType):
2106+
seen_tvt = True
2107+
valid_tvar_defs.append(tv)
2108+
defn.type_vars = valid_tvar_defs
20882109
defn.info.type_vars = []
20892110
# we want to make sure any additional logic in add_type_vars gets run
20902111
defn.info.add_type_vars()
@@ -4017,6 +4038,28 @@ def analyze_alias(
40174038
with self.allow_unbound_tvars_set():
40184039
rvalue.accept(self)
40194040

4041+
new_tvar_defs = []
4042+
erase_tvar_defs = []
4043+
variadic = False
4044+
for td in tvar_defs:
4045+
if variadic and isinstance(td, TypeVarType) and td.has_default():
4046+
self.fail(
4047+
message_registry.NO_DEFAULT_AFTER_TYPEVAR_TUPLE,
4048+
rvalue,
4049+
code=codes.TYPE_VAR,
4050+
)
4051+
# Remove the ambiguous type variable, and record it, so that we can
4052+
# replace all its uses with Any.
4053+
erase_tvar_defs.append(td)
4054+
continue
4055+
if isinstance(td, TypeVarTupleType):
4056+
# There can be only one variadic variable at most,
4057+
# the error is reported elsewhere.
4058+
if variadic:
4059+
continue
4060+
variadic = True
4061+
new_tvar_defs.append(td)
4062+
40204063
analyzed, depends_on = analyze_type_alias(
40214064
typ,
40224065
self,
@@ -4029,20 +4072,11 @@ def analyze_alias(
40294072
in_dynamic_func=dynamic,
40304073
global_scope=global_scope,
40314074
allowed_alias_tvars=tvar_defs,
4075+
erase_tvar_defs=erase_tvar_defs,
40324076
alias_type_params_names=all_declared_type_params_names,
40334077
python_3_12_type_alias=python_3_12_type_alias,
40344078
)
40354079

4036-
# There can be only one variadic variable at most, the error is reported elsewhere.
4037-
new_tvar_defs = []
4038-
variadic = False
4039-
for td in tvar_defs:
4040-
if isinstance(td, TypeVarTupleType):
4041-
if variadic:
4042-
continue
4043-
variadic = True
4044-
new_tvar_defs.append(td)
4045-
40464080
indexed = bool(isinstance(typ, UnboundType) and (typ.args or typ.empty_tuple_index))
40474081
default_depends = {}
40484082
for _, tv in alias_type_vars:
@@ -5771,7 +5805,10 @@ def visit_type_alias_stmt(self, s: TypeAliasStmt) -> None:
57715805
res = make_any_non_unimported(res)
57725806
eager = self.is_func_scope()
57735807
if isinstance(res, ProperType) and isinstance(res, Instance):
5774-
fix_instance(res, self.fail, self.note, disallow_any=False, options=self.options)
5808+
if not validate_instance(res, self.fail, indexed):
5809+
fix_instance(
5810+
res, self.fail, self.note, disallow_any=False, options=self.options
5811+
)
57755812
alias_node = TypeAlias(
57765813
res,
57775814
self.qualified_name(s.name.name),
@@ -6396,7 +6433,7 @@ def analyze_comp_for(self, expr: GeneratorExpr | DictionaryComprehension) -> Non
63966433
if i > 0:
63976434
sequence.accept(self)
63986435
# Bind index variables.
6399-
self.analyze_lvalue(index)
6436+
self.analyze_lvalue(index, is_index_var=True)
64006437
for cond in conditions:
64016438
cond.accept(self)
64026439

@@ -7789,6 +7826,7 @@ def type_analyzer(
77897826
prohibit_special_class_field_types=prohibit_special_class_field_types,
77907827
allow_type_any=allow_type_any,
77917828
analyzing_tvar_def=analyzing_tvar_def,
7829+
erase_tvar_defs=self.removed_type_vars[-1],
77927830
)
77937831
tpan.in_dynamic_func = bool(self.function_stack and self.function_stack[-1].is_dynamic())
77947832
tpan.global_scope = not self.type and not self.function_stack

0 commit comments

Comments
 (0)