Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 660018c

Browse files
ddfisherJukkaL
authored andcommitted
Make strict Optional type system changes standard (#3024)
* Move over most strict optional changes * Fix None in Unions * Kill Void * Add better way to report use of returned None's * Remove old way to warn on returned None's * Fix tests
1 parent 2b3a884 commit 660018c

40 files changed

+265
-527
lines changed

mypy/applytype.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def apply_generic_arguments(callable: CallableType, types: List[Type],
4242

4343
upper_bound = callable.variables[i].upper_bound
4444
if (type and not isinstance(type, PartialType) and
45-
not mypy.subtypes.satisfies_upper_bound(type, upper_bound)):
45+
not mypy.subtypes.is_subtype(type, upper_bound)):
4646
msg.incompatible_typevar_value(callable, i + 1, type, context)
4747

4848
# Create a map from type variable id to target type.

mypy/checker.py

+46-72
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
)
2626
from mypy import nodes
2727
from mypy.types import (
28-
Type, AnyType, CallableType, Void, FunctionLike, Overloaded, TupleType, TypedDictType,
28+
Type, AnyType, CallableType, FunctionLike, Overloaded, TupleType, TypedDictType,
2929
Instance, NoneTyp, ErrorType, strip_type, TypeType,
3030
UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarDef,
3131
true_only, false_only, function_type, is_named_instance
@@ -300,7 +300,7 @@ def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None:
300300
#
301301
# A classic generator must define a return type that's either
302302
# `Generator[ty, tc, tr]`, Iterator[ty], or Iterable[ty] (or
303-
# object or Any). If tc/tr are not given, both are Void.
303+
# object or Any). If tc/tr are not given, both are None.
304304
#
305305
# A coroutine must define a return type corresponding to tr; the
306306
# other two are unconstrained. The "external" return type (seen
@@ -377,11 +377,6 @@ def get_generator_yield_type(self, return_type: Type, is_coroutine: bool) -> Typ
377377
# AwaitableGenerator, Generator, AsyncGenerator, Iterator, or Iterable; ty is args[0].
378378
ret_type = return_type.args[0]
379379
# TODO not best fix, better have dedicated yield token
380-
if isinstance(ret_type, NoneTyp):
381-
if experiments.STRICT_OPTIONAL:
382-
return NoneTyp(is_ret_type=True)
383-
else:
384-
return Void()
385380
return ret_type
386381
else:
387382
# If the function's declared supertype of Generator has no type
@@ -414,10 +409,7 @@ def get_generator_receive_type(self, return_type: Type, is_coroutine: bool) -> T
414409
else:
415410
# `return_type` is a supertype of Generator, so callers won't be able to send it
416411
# values. IOW, tc is None.
417-
if experiments.STRICT_OPTIONAL:
418-
return NoneTyp(is_ret_type=True)
419-
else:
420-
return Void()
412+
return NoneTyp()
421413

422414
def get_generator_return_type(self, return_type: Type, is_coroutine: bool) -> Type:
423415
"""Given the declared return type of a generator (t), return the type it returns (tr)."""
@@ -529,7 +521,7 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: str) -> None:
529521
if fdef:
530522
# Check if __init__ has an invalid, non-None return type.
531523
if (fdef.info and fdef.name() in ('__init__', '__init_subclass__') and
532-
not isinstance(typ.ret_type, (Void, NoneTyp)) and
524+
not isinstance(typ.ret_type, NoneTyp) and
533525
not self.dynamic_funcs[-1]):
534526
self.fail(messages.MUST_HAVE_NONE_RETURN_TYPE.format(fdef.name()),
535527
item.type)
@@ -572,7 +564,7 @@ def is_implicit_any(t: Type) -> bool:
572564
if (self.options.python_version[0] == 2 and
573565
isinstance(typ.ret_type, Instance) and
574566
typ.ret_type.type.fullname() == 'typing.Generator'):
575-
if not isinstance(typ.ret_type.args[2], (Void, NoneTyp, AnyType)):
567+
if not isinstance(typ.ret_type.args[2], (NoneTyp, AnyType)):
576568
self.fail(messages.INVALID_GENERATOR_RETURN_ITEM_TYPE, typ)
577569

578570
# Fix the type if decorated with `@types.coroutine` or `@asyncio.coroutine`.
@@ -660,7 +652,7 @@ def is_implicit_any(t: Type) -> bool:
660652
else:
661653
return_type = self.return_types[-1]
662654

663-
if (not isinstance(return_type, (Void, NoneTyp, AnyType))
655+
if (not isinstance(return_type, (NoneTyp, AnyType))
664656
and not self.is_trivial_body(defn.body)):
665657
# Control flow fell off the end of a function that was
666658
# declared to return a non-None type and is not
@@ -1149,11 +1141,8 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type
11491141
partial_types = self.find_partial_types(var)
11501142
if partial_types is not None:
11511143
if not self.current_node_deferred:
1152-
if experiments.STRICT_OPTIONAL:
1153-
var.type = UnionType.make_simplified_union(
1154-
[rvalue_type, NoneTyp()])
1155-
else:
1156-
var.type = rvalue_type
1144+
var.type = UnionType.make_simplified_union(
1145+
[rvalue_type, NoneTyp()])
11571146
else:
11581147
var.type = None
11591148
del partial_types[var]
@@ -1554,10 +1543,7 @@ def is_definition(self, s: Lvalue) -> bool:
15541543
def infer_variable_type(self, name: Var, lvalue: Lvalue,
15551544
init_type: Type, context: Context) -> None:
15561545
"""Infer the type of initialized variables from initializer type."""
1557-
if self.is_unusable_type(init_type):
1558-
self.check_usable_type(init_type, context)
1559-
self.set_inference_error_fallback_type(name, lvalue, init_type, context)
1560-
elif isinstance(init_type, DeletedType):
1546+
if isinstance(init_type, DeletedType):
15611547
self.msg.deleted_as_rvalue(init_type, context)
15621548
elif not is_valid_inferred_type(init_type):
15631549
# We cannot use the type of the initialization expression for full type
@@ -1748,7 +1734,7 @@ def try_infer_partial_type_from_indexed_assignment(
17481734
del partial_types[var]
17491735

17501736
def visit_expression_stmt(self, s: ExpressionStmt) -> None:
1751-
self.expr_checker.accept(s.expr)
1737+
self.expr_checker.accept(s.expr, allow_none_return=True)
17521738

17531739
def visit_return_stmt(self, s: ReturnStmt) -> None:
17541740
"""Type check a return statement."""
@@ -1769,13 +1755,25 @@ def check_return_stmt(self, s: ReturnStmt) -> None:
17691755
return
17701756

17711757
if s.expr:
1758+
is_lambda = isinstance(self.scope.top_function(), FuncExpr)
1759+
declared_none_return = isinstance(return_type, NoneTyp)
1760+
declared_any_return = isinstance(return_type, AnyType)
1761+
1762+
# This controls whether or not we allow a function call that
1763+
# returns None as the expression of this return statement.
1764+
# E.g. `return f()` for some `f` that returns None. We allow
1765+
# this only if we're in a lambda or in a function that returns
1766+
# `None` or `Any`.
1767+
allow_none_func_call = is_lambda or declared_none_return or declared_any_return
1768+
17721769
# Return with a value.
1773-
typ = self.expr_checker.accept(s.expr, return_type)
1770+
typ = self.expr_checker.accept(s.expr,
1771+
return_type,
1772+
allow_none_return=allow_none_func_call)
17741773

17751774
if defn.is_async_generator:
17761775
self.fail("'return' with value in async generator is not allowed", s)
17771776
return
1778-
17791777
# Returning a value of type Any is always fine.
17801778
if isinstance(typ, AnyType):
17811779
# (Unless you asked to be warned in that case, and the
@@ -1784,10 +1782,12 @@ def check_return_stmt(self, s: ReturnStmt) -> None:
17841782
self.warn(messages.RETURN_ANY.format(return_type), s)
17851783
return
17861784

1787-
if self.is_unusable_type(return_type):
1788-
# Lambdas are allowed to have a unusable returns.
1789-
# Functions returning a value of type None are allowed to have a Void return.
1790-
if isinstance(self.scope.top_function(), FuncExpr) or isinstance(typ, NoneTyp):
1785+
# Disallow return expressions in functions declared to return
1786+
# None, subject to two exceptions below.
1787+
if declared_none_return:
1788+
# Lambdas are allowed to have None returns.
1789+
# Functions returning a value of type None are allowed to have a None return.
1790+
if is_lambda or isinstance(typ, NoneTyp):
17911791
return
17921792
self.fail(messages.NO_RETURN_VALUE_EXPECTED, s)
17931793
else:
@@ -1805,7 +1805,7 @@ def check_return_stmt(self, s: ReturnStmt) -> None:
18051805
isinstance(return_type, AnyType)):
18061806
return
18071807

1808-
if isinstance(return_type, (Void, NoneTyp, AnyType)):
1808+
if isinstance(return_type, (NoneTyp, AnyType)):
18091809
return
18101810

18111811
if self.in_checked_function():
@@ -1818,7 +1818,6 @@ def visit_if_stmt(self, s: IfStmt) -> None:
18181818
with self.binder.frame_context(can_skip=False, fall_through=0):
18191819
for e, b in zip(s.expr, s.body):
18201820
t = self.expr_checker.accept(e)
1821-
self.check_usable_type(t, e)
18221821

18231822
if isinstance(t, DeletedType):
18241823
self.msg.deleted_as_rvalue(t, s)
@@ -2058,8 +2057,6 @@ def analyze_async_iterable_item_type(self, expr: Expression) -> Type:
20582057
echk = self.expr_checker
20592058
iterable = echk.accept(expr)
20602059

2061-
self.check_usable_type(iterable, expr)
2062-
20632060
self.check_subtype(iterable,
20642061
self.named_generic_type('typing.AsyncIterable',
20652062
[AnyType()]),
@@ -2077,12 +2074,8 @@ def analyze_iterable_item_type(self, expr: Expression) -> Type:
20772074
echk = self.expr_checker
20782075
iterable = echk.accept(expr)
20792076

2080-
self.check_usable_type(iterable, expr)
20812077
if isinstance(iterable, TupleType):
2082-
if experiments.STRICT_OPTIONAL:
2083-
joined = UninhabitedType() # type: Type
2084-
else:
2085-
joined = NoneTyp()
2078+
joined = UninhabitedType() # type: Type
20862079
for item in iterable.items:
20872080
joined = join_types(joined, item)
20882081
if isinstance(joined, ErrorType):
@@ -2119,7 +2112,7 @@ def visit_del_stmt(self, s: DelStmt) -> None:
21192112
m.line = s.line
21202113
c = CallExpr(m, [e.index], [nodes.ARG_POS], [None])
21212114
c.line = s.line
2122-
c.accept(self.expr_checker)
2115+
self.expr_checker.accept(c, allow_none_return=True)
21232116
else:
21242117
s.expr.accept(self.expr_checker)
21252118
for elt in flatten(s.expr):
@@ -2248,21 +2241,18 @@ def check_subtype(self, subtype: Type, supertype: Type, context: Context,
22482241
if is_subtype(subtype, supertype):
22492242
return True
22502243
else:
2251-
if self.is_unusable_type(subtype):
2252-
self.msg.does_not_return_value(subtype, context)
2253-
else:
2254-
if self.should_suppress_optional_error([subtype]):
2255-
return False
2256-
extra_info = [] # type: List[str]
2257-
if subtype_label is not None or supertype_label is not None:
2258-
subtype_str, supertype_str = self.msg.format_distinctly(subtype, supertype)
2259-
if subtype_label is not None:
2260-
extra_info.append(subtype_label + ' ' + subtype_str)
2261-
if supertype_label is not None:
2262-
extra_info.append(supertype_label + ' ' + supertype_str)
2263-
if extra_info:
2264-
msg += ' (' + ', '.join(extra_info) + ')'
2265-
self.fail(msg, context)
2244+
if self.should_suppress_optional_error([subtype]):
2245+
return False
2246+
extra_info = [] # type: List[str]
2247+
if subtype_label is not None or supertype_label is not None:
2248+
subtype_str, supertype_str = self.msg.format_distinctly(subtype, supertype)
2249+
if subtype_label is not None:
2250+
extra_info.append(subtype_label + ' ' + subtype_str)
2251+
if supertype_label is not None:
2252+
extra_info.append(supertype_label + ' ' + supertype_str)
2253+
if extra_info:
2254+
msg += ' (' + ', '.join(extra_info) + ')'
2255+
self.fail(msg, context)
22662256
return False
22672257

22682258
def contains_none(self, t: Type) -> bool:
@@ -2369,8 +2359,7 @@ def enter_partial_types(self) -> Iterator[None]:
23692359
partial_types = self.partial_types.pop()
23702360
if not self.current_node_deferred:
23712361
for var, context in partial_types.items():
2372-
if (experiments.STRICT_OPTIONAL and
2373-
isinstance(var.type, PartialType) and var.type.type is None):
2362+
if isinstance(var.type, PartialType) and var.type.type is None:
23742363
# None partial type: assume variable is intended to have type None
23752364
var.type = NoneTyp()
23762365
else:
@@ -2383,18 +2372,6 @@ def find_partial_types(self, var: Var) -> Optional[Dict[Var, Context]]:
23832372
return partial_types
23842373
return None
23852374

2386-
def is_unusable_type(self, typ: Type) -> bool:
2387-
"""Is this type an unusable type?
2388-
2389-
The two unusable types are Void and NoneTyp(is_ret_type=True).
2390-
"""
2391-
return isinstance(typ, Void) or (isinstance(typ, NoneTyp) and typ.is_ret_type)
2392-
2393-
def check_usable_type(self, typ: Type, context: Context) -> None:
2394-
"""Generate an error if the type is not a usable type."""
2395-
if self.is_unusable_type(typ):
2396-
self.msg.does_not_return_value(typ, context)
2397-
23982375
def temp_node(self, t: Type, context: Context = None) -> TempNode:
23992376
"""Create a temporary node with the given, fixed type."""
24002377
temp = TempNode(t)
@@ -2925,9 +2902,6 @@ def is_valid_inferred_type_component(typ: Type) -> bool:
29252902
In strict Optional mode this excludes bare None types, as otherwise every
29262903
type containing None would be invalid.
29272904
"""
2928-
if not experiments.STRICT_OPTIONAL:
2929-
if is_same_type(typ, NoneTyp()):
2930-
return False
29312905
if is_same_type(typ, UninhabitedType()):
29322906
return False
29332907
elif isinstance(typ, Instance):

0 commit comments

Comments
 (0)