Skip to content

Commit 01e24c2

Browse files
committed
Minor tweaks: change if statment order; add tests; fix comment style
1 parent 4356244 commit 01e24c2

File tree

2 files changed

+46
-30
lines changed

2 files changed

+46
-30
lines changed

mypy/checker.py

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -453,16 +453,16 @@ def get_generator_yield_type(self, return_type: Type) -> Type:
453453
if isinstance(return_type, AnyType):
454454
return AnyType()
455455
elif not self.is_generator_return_type(return_type):
456-
# if the function doesn't have a proper Generator (or superclass)
457-
# return type, anything is permissible
456+
# If the function doesn't have a proper Generator (or superclass) return type, anything
457+
# is permissible.
458458
return AnyType()
459459
elif not isinstance(return_type, Instance):
460-
# same as above, but written as a separate branch so the typechecker can understand
460+
# Same as above, but written as a separate branch so the typechecker can understand.
461461
return AnyType()
462462
elif return_type.args:
463463
return return_type.args[0]
464464
else:
465-
# if the function's declared supertype of Generator has no type
465+
# If the function's declared supertype of Generator has no type
466466
# parameters (i.e. is `object`), then the yielded values can't
467467
# be accessed so any type is acceptable.
468468
return AnyType()
@@ -471,35 +471,37 @@ def get_generator_receive_type(self, return_type: Type) -> Type:
471471
if isinstance(return_type, AnyType):
472472
return AnyType()
473473
elif not self.is_generator_return_type(return_type):
474-
# if the function doesn't have a proper Generator (or superclass)
475-
# return type, anything is permissible
474+
# If the function doesn't have a proper Generator (or superclass) return type, anything
475+
# is permissible.
476476
return AnyType()
477477
elif not isinstance(return_type, Instance):
478-
# same as above, but written as a separate branch so the typechecker can understand
478+
# Same as above, but written as a separate branch so the typechecker can understand.
479479
return AnyType()
480480
elif return_type.type.fullname() == 'typing.Generator':
481-
# Generator is the only type which specifies the type of values it can receive
481+
# Generator is the only type which specifies the type of values it can receive.
482482
return return_type.args[1]
483483
else:
484-
# it's a supertype of Generator, so callers won't be able to see send it values
484+
# `return_type` is a supertype of Generator, so callers won't be able to send it
485+
# values.
485486
return Void()
486487

487488
def get_generator_return_type(self, return_type: Type) -> Type:
488489
if isinstance(return_type, AnyType):
489490
return AnyType()
490491
elif not self.is_generator_return_type(return_type):
491-
# if the function doesn't have a proper Generator (or superclass)
492-
# return type, anything is permissible
492+
# If the function doesn't have a proper Generator (or superclass) return type, anything
493+
# is permissible.
493494
return AnyType()
494495
elif not isinstance(return_type, Instance):
495-
# same as above, but written as a separate branch so the typechecker can understand
496+
# Same as above, but written as a separate branch so the typechecker can understand.
496497
return AnyType()
497498
elif return_type.type.fullname() == 'typing.Generator':
498-
# Generator is the only type which specifies the type of values it
499-
# returns into `yield from` expressions
499+
# Generator is the only type which specifies the type of values it returns into
500+
# `yield from` expressions.
500501
return return_type.args[2]
501502
else:
502-
# it's a supertype of Generator, so callers won't be able to see the return type
503+
# `return_type` is supertype of Generator, so callers won't be able to see the return
504+
# type when used in a `yield from` expression.
503505
return AnyType()
504506

505507
def visit_func_def(self, defn: FuncDef) -> Type:
@@ -612,12 +614,12 @@ def check_func_def(self, defn: FuncItem, typ: CallableType, name: str) -> None:
612614
self.fail(messages.RETURN_TYPE_CANNOT_BE_CONTRAVARIANT,
613615
typ.ret_type)
614616

615-
# check that Generator functions have the appropriate return type
617+
# Check that Generator functions have the appropriate return type.
616618
if defn.is_generator:
617619
if not self.is_generator_return_type(typ.ret_type):
618620
self.fail(messages.INVALID_RETURN_TYPE_FOR_GENERATOR, typ)
619621

620-
# Python 2 generators aren't allowed to return values
622+
# Python 2 generators aren't allowed to return values.
621623
if (self.pyversion[0] == 2 and
622624
isinstance(typ.ret_type, Instance) and
623625
typ.ret_type.type.fullname() == 'typing.Generator'):
@@ -1484,11 +1486,10 @@ def visit_return_stmt(self, s: ReturnStmt) -> Type:
14841486
return None
14851487

14861488
if isinstance(return_type, Void):
1487-
# FuncExpr (lambda) may have a Void return.
1488-
# Function returning a value of type None may have a Void return.
1489+
# Lambdas are allowed to have a Void return.
1490+
# Functions returning a value of type None are allowed to have a Void return.
14891491
if isinstance(self.function_stack[-1], FuncExpr) or isinstance(typ, NoneTyp):
14901492
return None
1491-
14921493
self.fail(messages.NO_RETURN_VALUE_EXPECTED, s)
14931494
else:
14941495
self.check_subtype(
@@ -1497,7 +1498,7 @@ def visit_return_stmt(self, s: ReturnStmt) -> Type:
14971498
+ ": expected {}, got {}".format(return_type, typ)
14981499
)
14991500
else:
1500-
# empty returns are valid in Generators with Any typed returns
1501+
# Empty returns are valid in Generators with Any typed returns.
15011502
if (self.function_stack[-1].is_generator and isinstance(return_type, AnyType)):
15021503
return None
15031504

@@ -1861,9 +1862,11 @@ def visit_yield_from_expr(self, e: YieldFromExpr) -> Type:
18611862
return_type = self.return_types[-1]
18621863
subexpr_type = self.accept(e.expr, return_type)
18631864

1864-
# check that the expr is an instance of Iterable and get the type of
1865-
# the iterator produced by __iter__
1866-
if (isinstance(subexpr_type, Instance) and
1865+
# Check that the expr is an instance of Iterable and get the type of the iterator produced
1866+
# by __iter__.
1867+
if isinstance(subexpr_type, AnyType):
1868+
iter_type = AnyType()
1869+
elif (isinstance(subexpr_type, Instance) and
18671870
is_subtype(subexpr_type, self.named_type('typing.Iterable'))):
18681871
iter_method_type = self.expr_checker.analyze_external_member_access(
18691872
'__iter__',
@@ -1874,27 +1877,25 @@ def visit_yield_from_expr(self, e: YieldFromExpr) -> Type:
18741877
[AnyType(), AnyType(), AnyType()])
18751878
iter_type, _ = self.expr_checker.check_call(iter_method_type, [], [],
18761879
context=generic_generator_type)
1877-
elif isinstance(subexpr_type, AnyType):
1878-
iter_type = AnyType()
18791880
else:
18801881
self.msg.yield_from_invalid_operand_type(subexpr_type, e)
18811882
iter_type = AnyType()
18821883

1883-
# check that the iterator's item type matches the type yielded by the
1884-
# Generator function containing this yield from
1884+
# Check that the iterator's item type matches the type yielded by the Generator function
1885+
# containing this `yield from` expression.
18851886
expected_item_type = self.get_generator_yield_type(return_type)
18861887
actual_item_type = self.get_generator_yield_type(iter_type)
18871888

18881889
self.check_subtype(actual_item_type, expected_item_type, e,
18891890
messages.INCOMPATIBLE_TYPES_IN_YIELD_FROM,
18901891
'actual type', 'expected type')
18911892

1892-
# determine the type of the entire yield from expression
1893+
# Determine the type of the entire yield from expression.
18931894
if (isinstance(iter_type, Instance) and
18941895
iter_type.type.fullname() == 'typing.Generator'):
18951896
return self.get_generator_return_type(iter_type)
18961897
else:
1897-
# non-Generators don't return anything from "yield from" expressions
1898+
# Non-Generators don't return anything from `yield from` expressions.
18981899
return Void()
18991900

19001901
def visit_member_expr(self, e: MemberExpr) -> Type:

mypy/test/data/check-statements.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@ def f() -> Generator[int, None, str]:
6666
[out]
6767
main: note: In function "f":
6868

69+
[case testEmptyReturnInNoneTypedGenerator]
70+
from typing import Generator
71+
def f() -> Generator[int, None, None]:
72+
yield 1
73+
return
74+
[out]
75+
76+
[case testNonEmptyReturnInNoneTypedGenerator]
77+
from typing import Generator
78+
def f() -> Generator[int, None, None]:
79+
yield 1
80+
return 42 # E: No return value expected
81+
[out]
82+
main: note: In function "f":
83+
6984
[case testReturnInIterator]
7085
from typing import Iterator
7186
def f() -> Iterator[int]:

0 commit comments

Comments
 (0)